I'm using the Programming RPG's With DirectX engines, and the Input engine works good for the keyboard, except for the arrow keys, and I can't figure out what's wrong. If I do a test with the arrow keys it acts as though the key is constantly being pressed, even though it hasn't been pressed at all yet. I've only noticed it for the DIK_LEFT, DIK_RIGHT, DIK_UP, and DIK_DOWN keys. I've run the code he gives in chapter 7 which shows just the basic setup of keyboard input, and that works fine so I know it's not anything with my keyboard or anything. It's just the actual input engine that has the bug in it. Has anybody else noticed that, and more importantly, does anyone know how to fix it? Thanks.
Oh yeah, it's the 1st edition of the book, not the 2nd. If anybody has the 2nd edition, could you maybe email me the input engine for it, maybe it has fixed this bug. My email address is deadlydogAThotmail.com Thanks again.
Here's the input engine code if anyone wants to look through it.
Core_Input.h
/**************************************************
WinMain.cpp
GameCore Component
Programming Role-Playing Games with DirectX
by Jim Adams (01 Jan 2002)
**************************************************/
#ifndef _CORE_INPUT_H_
#define _CORE_INPUT_H_
// Macro to release COM objects
#define ReleaseCOM(x) if(x) { x->Release(); x = NULL; }
// Enumerated list of of device types
enum InputDevices {
NONE = 0,
KEYBOARD,
MOUSE,
JOYSTICK
};
///////////////////////////////////////////////////////////////////////
// Keyboard Key definitions
///////////////////////////////////////////////////////////////////////
#define KEY_RELEASED FALSE
#define KEY_PRESSED TRUE
#define KEY_UNLOCKED FALSE
#define KEY_LOCKED TRUE
#define KEY_ESC DIK_ESCAPE
#define KEY_ESCAPE DIK_ESCAPE
#define KEY_MINUS DIK_MINUS
#define KEY_EQUALS DIK_EQUALS
#define KEY_BACKSPACE DIK_BACK
#define KEY_TAB DIK_TAB
#define KEY_LBRACKET DIK_LBRACKET
#define KEY_RBRACKET DIK_RBRACKET
#define KEY_ENTER DIK_RETURN
#define KEY_RETURN DIK_RETURN
#define KEY_CTRL DIK_LCONTROL
#define KEY_LCTRL DIK_LCONTROL
#define KEY_RCTRL DIK_RCTRL
#define KEY_SHIFT DIK_LSHIFT
#define KEY_LSHIFT DIK_LSHIFT
#define KEY_RSHIFT DIK_RSHIFT
#define KEY_ALT DIK_LMENU
#define KEY_LALT DIK_LMENU
#define KEY_RALT DIK_RMENU
#define KEY_0 DIK_0
#define KEY_1 DIK_1
#define KEY_2 DIK_2
#define KEY_3 DIK_3
#define KEY_4 DIK_4
#define KEY_5 DIK_5
#define KEY_6 DIK_6
#define KEY_7 DIK_7
#define KEY_8 DIK_8
#define KEY_9 DIK_9
#define KEY_A DIK_A
#define KEY_B DIK_B
#define KEY_C DIK_C
#define KEY_D DIK_D
#define KEY_E DIK_E
#define KEY_F DIK_F
#define KEY_G DIK_G
#define KEY_H DIK_H
#define KEY_I DIK_I
#define KEY_J DIK_J
#define KEY_K DIK_K
#define KEY_L DIK_L
#define KEY_M DIK_M
#define KEY_N DIK_N
#define KEY_O DIK_O
#define KEY_P DIK_P
#define KEY_Q DIK_Q
#define KEY_R DIK_R
#define KEY_S DIK_S
#define KEY_T DIK_T
#define KEY_U DIK_U
#define KEY_V DIK_V
#define KEY_W DIK_W
#define KEY_X DIK_X
#define KEY_Y DIK_Y
#define KEY_Z DIK_Z
#define KEY_SEMICOLON DIK_SEMICOLON
#define KEY_APOSTROPHE DIK_APOSTROPHE
#define KEY_TILDE DIK_GRAVE
#define KEY_GRAVE DIK_GRAVE
#define KEY_BACKSLASH DIK_BACKSLASH
#define KEY_COMMA DIK_COMMA
#define KEY_PERIOD DIK_PERIOD
#define KEY_FORWARDSLASH DIK_SLASH
#define KEY_SLASH DIK_SLASH
#define KEY_SPACE DIK_SPACE
#define KEY_CAPSLOCK DIK_CAPITAL
#define KEY_CAPITAL DIK_CAPITAL
#define KEY_F1 DIK_F1
#define KEY_F2 DIK_F2
#define KEY_F3 DIK_F3
#define KEY_F4 DIK_F4
#define KEY_F5 DIK_F5
#define KEY_F6 DIK_F6
#define KEY_F7 DIK_F7
#define KEY_F8 DIK_F8
#define KEY_F9 DIK_F9
#define KEY_F10 DIK_F10
#define KEY_F11 DIK_F11
#define KEY_F12 DIK_F12
#define KEY_SYSRQ DIK_SYSRQ
#define KEY_SCROLLLOCK DIK_SCROLL
#define KEY_PAUSE DIK_PAUSE
#define KEY_NUMLOCK DIK_NUMLOCK
#define KEY_NUMPAD0 DIK_NUMPAD0
#define KEY_NUMPAD1 DIK_NUMPAD1
#define KEY_NUMPAD2 DIK_NUMPAD2
#define KEY_NUMPAD3 DIK_NUMPAD3
#define KEY_NUMPAD4 DIK_NUMPAD4
#define KEY_NUMPAD5 DIK_NUMPAD5
#define KEY_NUMPAD6 DIK_NUMPAD6
#define KEY_NUMPAD7 DIK_NUMPAD7
#define KEY_NUMPAD8 DIK_NUMPAD8
#define KEY_NUMPAD9 DIK_NUMPAD9
#define KEY_ADD DIK_ADD
#define KEY_SUBTRACT DIK_SUBTRACT
#define KEY_DIVIDE DIK_DEVICE
#define KEY_MULTIPLY DIK_MULTIPLY
#define KEY_DECIMAL DIK_DECIMAL
#define KEY_NUMPADENTER DIK_NUMPADENTER
#define KEY_INSERT DIK_INSERT
#define KEY_DELETE DIK_DELETE
#define KEY_HOME DIK_HOME
#define KEY_END DIK_END
#define KEY_PAGEUP DIK_PRIOR
#define KEY_PAGEDOWN DIK_NEXT
#define KEY_UP DIK_UP
#define KEY_DOWN DIK_DOWN
#define KEY_LEFT DIK_LEFT
#define KEY_RIGHT DIK_RIGHT
#define KEY_LWIN DIK_LWIN
#define KEY_RWIN DIK_RWIN
#define KEY_APPS DIK_APPS
///////////////////////////////////////////////////////////////////////
// Mouse and Joystick definitions
///////////////////////////////////////////////////////////////////////
#define BUTTON_RELEASED FALSE
#define BUTTON_PRESSED TRUE
#define BUTTON_UNLOCKED FALSE
#define BUTTON_LOCKED TRUE
#define MOUSE_LBUTTON 0
#define MOUSE_RBUTTON 1
#define MOUSE_MBUTTON 2
#define JOYSTICK_BUTTON0 0
#define JOYSTICK_BUTTON1 1
#define JOYSTICK_BUTTON2 2
#define JOYSTICK_BUTTON3 3
#define JOYSTICK_BUTTON4 4
#define JOYSTICK_BUTTON5 5
///////////////////////////////////////////////////////////////////////
// Class definitions
///////////////////////////////////////////////////////////////////////
class cInput;
class cInputDevice;
class cInput
{
protected:
HWND m_hWnd;
IDirectInput8 *m_pDI;
public:
cInput();
~cInput();
IDirectInput8 *GetDirectInputCOM();
HWND GethWnd();
BOOL Init(HWND hWnd, HINSTANCE hInst);
BOOL Shutdown();
};
class cInputDevice
{
public:
cInput *m_Input;
short m_Type;
IDirectInputDevice8 *m_pDIDevice;
BOOL m_Windowed;
char m_State[256];
DIMOUSESTATE *m_MouseState;
DIJOYSTATE *m_JoystickState;
BOOL m_Locks[256];
long m_XPos, m_YPos;
static BOOL FAR PASCAL EnumJoysticks(LPCDIDEVICEINSTANCE pdInst, LPVOID pvRef);
public:
cInputDevice();
~cInputDevice();
IDirectInputDevice8 *DeviceCOM();
// Generic functions - all devices
BOOL Create(cInput *Input, short Type, BOOL Windowed = TRUE);
BOOL Free();
BOOL Clear();
BOOL Read();
BOOL Acquire(BOOL Active = TRUE);
BOOL GetLock(char Num);
BOOL SetLock(char Num, BOOL State = TRUE);
long GetXPos();
BOOL SetXPos(long XPos);
long GetYPos();
BOOL SetYPos(long YPos);
long GetXDelta();
long GetYDelta();
// Keyboard specific functions
BOOL GetKeyState(char Num);
BOOL SetKeyState(char Num, BOOL State);
BOOL GetPureKeyState(char Num);
short GetKeypress(long TimeOut = 0);
long GetNumKeyPresses();
long GetNumPureKeyPresses();
// Mouse/Joystick specific functions
BOOL GetButtonState(char Num);
BOOL SetButtonState(char Num, BOOL State);
BOOL GetPureButtonState(char Num);
long GetNumButtonPresses();
long GetNumPureButtonPresses();
};
#endif
Core_Input.cpp
/**************************************************
WinMain.cpp
GameCore Component
Programming Role-Playing Games with DirectX
by Jim Adams (01 Jan 2002)
**************************************************/
#include "Core_Global.h"
///////////////////////////////////////////////////////////////////////
//
// cInput Class
//
///////////////////////////////////////////////////////////////////////
cInput::cInput()
{
// Only need to clear the DirectInput interface pointer
m_pDI = NULL;
}
cInput::~cInput()
{
// Force a shutdown
Shutdown();
}
HWND cInput::GethWnd()
{
// return the parent window handle
return m_hWnd;
}
IDirectInput8 *cInput::GetDirectInputCOM()
{
// return a pointer to IDirectInput8 object
return m_pDI;
}
BOOL cInput::Init(HWND hWnd, HINSTANCE hInst)
{
// Free a prior Init
Shutdown();
// Record parent Window handle
m_hWnd = hWnd;
// Create a DirectInput interface
if(FAILED(DirectInput8Create(hInst, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&m_pDI, NULL)))
return FALSE;
// Return a success
return TRUE;
}
BOOL cInput::Shutdown()
{
// Release the COM objects
ReleaseCOM(m_pDI);
// Clear parent Window handle
m_hWnd = NULL;
// Return a success
return TRUE;
}
///////////////////////////////////////////////////////////////////////
//
// cInputDevice Class
//
///////////////////////////////////////////////////////////////////////
cInputDevice::cInputDevice()
{
// Clear parent cInput object pointer
m_Input = NULL;
// Setup device to none
m_Type = NONE;
// Set windowed usage to TRUE
m_Windowed = TRUE;
// Clear the DirectInput interface pointer
m_pDIDevice = NULL;
// Point the mouse and joystick structures to the state buffer
m_MouseState = (DIMOUSESTATE*)&m_State;
m_JoystickState = (DIJOYSTATE*)&m_State;
// Clear the device variables
Clear();
}
cInputDevice::~cInputDevice()
{
// Free a prior install
Free();
}
IDirectInputDevice8 *cInputDevice::DeviceCOM()
{
// return the pointer to the IDirectDevice8 object
return m_pDIDevice;
}
BOOL cInputDevice::Create(cInput *Input, short Type, BOOL Windowed)
{
DIDATAFORMAT *DataFormat;
DIPROPRANGE DIprg;
DIPROPDWORD DIpdw;
// Free a prior device
Free();
// Check for a valid parent cInput class
if((m_Input = Input) == NULL)
return FALSE;
// Create the device and remember device data format
switch(Type) {
case KEYBOARD:
if(FAILED(m_Input->GetDirectInputCOM()->CreateDevice(GUID_SysKeyboard, &m_pDIDevice, NULL)))
return FALSE;
DataFormat = (DIDATAFORMAT*)&c_dfDIKeyboard;
break;
case MOUSE:
if(FAILED(m_Input->GetDirectInputCOM()->CreateDevice(GUID_SysMouse, &m_pDIDevice, NULL)))
return FALSE;
DataFormat = (DIDATAFORMAT*)&c_dfDIMouse;
break;
case JOYSTICK:
if(FAILED(m_Input->GetDirectInputCOM()->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumJoysticks, this, DIEDFL_ATTACHEDONLY)))
return FALSE;
if(m_pDIDevice == NULL)
return FALSE;
DataFormat = (DIDATAFORMAT*)&c_dfDIJoystick;
break;
default: return FALSE;
}
// Set the windowed usage
m_Windowed = Windowed;
// Set the data format of keyboard
if(FAILED(m_pDIDevice->SetDataFormat(DataFormat)))
return FALSE;
// Set the cooperative level - Foreground & Nonexclusive
if(FAILED(m_pDIDevice->SetCooperativeLevel(m_Input->GethWnd(), DISCL_FOREGROUND | DISCL_NONEXCLUSIVE)))
return FALSE;
// Set the special properties if it's a joystick
if(Type == JOYSTICK) {
// Set the special properties of the joystick - range
DIprg.diph.dwSize = sizeof(DIPROPRANGE);
DIprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
DIprg.diph.dwHow = DIPH_BYOFFSET;
DIprg.lMin = -1024;
DIprg.lMax = +1024;
// Set X range
DIprg.diph.dwObj = DIJOFS_X;
if(FAILED(m_pDIDevice->SetProperty(DIPROP_RANGE, &DIprg.diph)))
return FALSE;
// Set Y rangine
DIprg.diph.dwObj = DIJOFS_Y;
if(FAILED(m_pDIDevice->SetProperty(DIPROP_RANGE, &DIprg.diph)))
return FALSE;
// Set the special properties of the joystick - deadzone 12%
DIpdw.diph.dwSize = sizeof(DIPROPDWORD);
DIpdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
DIpdw.diph.dwHow = DIPH_BYOFFSET;
DIpdw.dwData = 128;
// Set X deadzone
DIpdw.diph.dwObj = DIJOFS_X;
if(FAILED(m_pDIDevice->SetProperty(DIPROP_DEADZONE, &DIpdw.diph)))
return FALSE;
// Set Y deadzone
DIpdw.diph.dwObj = DIJOFS_Y;
if(FAILED(m_pDIDevice->SetProperty(DIPROP_DEADZONE, &DIpdw.diph)))
return FALSE;
}
// Acquire the device for use
if(FAILED(m_pDIDevice->Acquire()))
return FALSE;
// Set the device type
m_Type = Type;
// Clear the device information
Clear();
// Return a success
return TRUE;
}
BOOL cInputDevice::Free()
{
// Unacquire and release the object
if(m_pDIDevice != NULL) {
m_pDIDevice->Unacquire();
ReleaseCOM(m_pDIDevice);
}
// Set to no device installed
m_Type = NONE;
// Clear the data
Clear();
return TRUE;
}
BOOL cInputDevice::Clear()
{
short i;
ZeroMemory(&m_State, 256);
for(i=0;i<256;i++)
m_Locks = FALSE;
m_XPos = 0;
m_YPos = 0;
return TRUE;
}
BOOL cInputDevice::Read()
{
HRESULT hr;
long BufferSizes[3] = { 256, sizeof(DIMOUSESTATE), sizeof(DIJOYSTATE) };
short i;
// Make sure to have a valid IDirectInputDevice8 object
if(m_pDIDevice == NULL)
return FALSE;
// Make sure device type if in range
if(m_Type < 1 || m_Type > 3)
return FALSE;
// Loop polling and reading until succeeded or unknown error
// Also take care of lost-focus problems
while(1) {
// Poll
m_pDIDevice->Poll();
// Read in state
if(SUCCEEDED(hr = m_pDIDevice->GetDeviceState(BufferSizes[m_Type-1], (LPVOID)&m_State)))
break;
// Return on an unknown error
if(hr != DIERR_INPUTLOST && hr != DIERR_NOTACQUIRED)
return FALSE;
// Reacquire and try again
if(FAILED(m_pDIDevice->Acquire()))
return FALSE;
}
// Since only the mouse coordinates are relative, you'll
// have to deal with them now
if(m_Type == MOUSE) {
// If windowed usage, ask windows for coordinates
if(m_Windowed == TRUE) {
POINT pt;
GetCursorPos(&pt);
ScreenToClient(m_Input->GethWnd(), &pt);
m_XPos = pt.x;
m_YPos = pt.y;
} else {
m_XPos += m_MouseState->lX;
m_YPos += m_MouseState->lY;
}
}
// Released keys and button need to be unlocked
switch(m_Type) {
case KEYBOARD:
for(i=0;i<256;i++) {
if(!(m_State & 0x80))
m_Locks = FALSE;
}
break;
case MOUSE:
for(i=0;i<4;i++) {
if(!(m_MouseState->rgbButtons))
m_Locks = FALSE;
}
break;
case JOYSTICK:
for(i=0;i<32;i++) {
if(!(m_JoystickState->rgbButtons))
m_Locks = FALSE;
}
break;
}
// return a success
return TRUE;
}
BOOL cInputDevice::Acquire(BOOL Active)
{
if(m_pDIDevice == NULL)
return FALSE;
if(Active == TRUE)
m_pDIDevice->Acquire();
else
m_pDIDevice->Unacquire();
return TRUE;
}
BOOL cInputDevice::GetLock(char Num)
{
return m_Locks[Num];
}
BOOL cInputDevice::SetLock(char Num, BOOL State)
{
m_Locks[Num] = State;
return TRUE;
}
long cInputDevice::GetXPos()
{
// Update coordinates if a joystick
if(m_Type == JOYSTICK)
m_XPos = m_JoystickState->lX;
return m_XPos;
}
BOOL cInputDevice::SetXPos(long XPos)
{
m_XPos = XPos;
return TRUE;
}
long cInputDevice::GetYPos()
{
// Update coordinates if a joystick
if(m_Type == JOYSTICK)
m_YPos = m_JoystickState->lY;
return m_YPos;
}
BOOL cInputDevice::SetYPos(long YPos)
{
m_YPos = YPos;
return TRUE;
}
long cInputDevice::GetXDelta()
{
switch(m_Type) {
case MOUSE:
return m_MouseState->lX;
case JOYSTICK:
return m_JoystickState->lX - m_XPos;
default: return 0;
}
}
long cInputDevice::GetYDelta()
{
switch(m_Type) {
case MOUSE:
return m_MouseState->lY;
case JOYSTICK:
return m_JoystickState->lY - m_YPos;
default: return 0;
}
}
BOOL cInputDevice::GetKeyState(char Num)
{
// Check if key/button is pressed
if(m_State[Num] & 0x80 && m_Locks[Num] == FALSE)
return TRUE;
return FALSE;
}
BOOL cInputDevice::SetKeyState(char Num, BOOL State)
{
m_State[Num] = State;
return TRUE;
}
BOOL cInputDevice::GetPureKeyState(char Num)
{
return ((m_State[Num] & 0x80) ? TRUE : FALSE);
}
short cInputDevice::GetKeypress(long TimeOut)
{
static HKL KeyboardLayout = GetKeyboardLayout(0);
unsigned char WinKeyStates[256], DIKeyStates[256];
unsigned short i, ScanCode, VirtualKey, Keys, Num;
unsigned long EndTime;
// Make sure it's a keyboard and its initialized
if((m_Type != KEYBOARD) || (m_pDIDevice == NULL))
return 0;
// Calculate end time for TimeOut
EndTime = GetTickCount() + TimeOut;
// Loop until timeout or key pressed
while(1) {
// Get Windows keyboard state
GetKeyboardState(WinKeyStates);
// Get DirectInput keyboard state
m_pDIDevice->GetDeviceState(256, DIKeyStates);
// Scan through looking for key presses
for(i=0;i<256;i++) {
// If one found, try to convert it
if(DIKeyStates & 0x80) {
// Get virtual key code
if((VirtualKey = MapVirtualKeyEx((ScanCode = i), 1, KeyboardLayout))) {
// Get ASCII code of key and return it
Num = ToAsciiEx(VirtualKey, ScanCode, WinKeyStates, &Keys, 0, KeyboardLayout);
if(Num)
return Keys;
}
}
}
// Check for TimeOut
if(TimeOut) {
if(GetTickCount() > EndTime)
return 0;
}
}
return 0;
}
long cInputDevice::GetNumKeyPresses()
{
long i, Num = 0;
for(i=0;i<256;i++) {
if(m_State & 0x80 && m_Locks == FALSE)
Num++;
}
return Num;
}
long cInputDevice::GetNumPureKeyPresses()
{
long i, Num = 0;
for(i=0;i<256;i++) {
if(m_State & 0x80)
Num++;
}
return Num;
}
BOOL cInputDevice::GetButtonState(char Num)
{
char State = 0;
if(m_Type == MOUSE)
State = m_MouseState->rgbButtons[Num];
if(m_Type == JOYSTICK)
State = m_JoystickState->rgbButtons[Num];
// Check if key/button is pressed
if(State & 0x80 && m_Locks[Num] == FALSE)
return TRUE;
return FALSE;
}
BOOL cInputDevice::SetButtonState(char Num, BOOL State)
{
if(m_Type == MOUSE) {
m_MouseState->rgbButtons[Num] = State;
return TRUE;
}
if(m_Type == JOYSTICK) {
m_JoystickState->rgbButtons[Num] = State;
return TRUE;
}
return FALSE;
}
BOOL cInputDevice::GetPureButtonState(char Num)
{
if(m_Type == MOUSE)
return m_MouseState->rgbButtons[Num];
if(m_Type == JOYSTICK)
return m_JoystickState->rgbButtons[Num];
return FALSE;
}
long cInputDevice::GetNumButtonPresses()
{
long i, Num = 0;
if(m_Type == MOUSE) {
for(i=0;i<4;i++) {
if(m_MouseState->rgbButtons & 0x80 && m_Locks == FALSE)
Num++;
}
} else
if(m_Type == JOYSTICK) {
for(i=0;i<32;i++) {
if(m_JoystickState->rgbButtons & 0x80 && m_Locks == FALSE)
Num++;
}
}
return Num;
}
long cInputDevice::GetNumPureButtonPresses()
{
long i, Num = 0;
if(m_Type == MOUSE) {
for(i=0;i<4;i++) {
if(m_MouseState->rgbButtons & 0x80)
Num++;
}
} else
if(m_Type == JOYSTICK) {
for(i=0;i<32;i++) {
if(m_JoystickState->rgbButtons & 0x80)
Num++;
}
}
return Num;
}
BOOL FAR PASCAL cInputDevice::EnumJoysticks(LPCDIDEVICEINSTANCE pdInst, LPVOID pvRef)
{
cInputDevice *Input;
// Stop enumeration if no parent cInputDevice pointer
if((Input = (cInputDevice*)pvRef) == NULL)
return DIENUM_STOP;
// Try to create a joystick interface
if(FAILED(Input->m_Input->GetDirectInputCOM()->CreateDevice(pdInst->guidInstance, &Input->m_pDIDevice, NULL)))
return DIENUM_CONTINUE;
// All done - stop enumeration
return DIENUM_STOP;
}
[Edited by - deadlydog on November 12, 2004 10:33:45 PM]