DirectX is an API that has direct access to your hardware, assuming that you have Windows9X/NT/2000/XP. The beauty of it is that you don't have to write separate code for each graphic card, sound card, and input device. DirectX handles the details, which is good because it isn't the easiest thing in the world to program, anyway. This tutorial will show you how to access the keyboard using DirectInput8. First of all, you have to include dinput.h. Also, you have to link dxguid.lib and dinput8.lib.
DirectInput is the easiest part of the DirectX API that I have worked with. Let's take a look at some initialization code.
// Globals
LPDIRECTINPUT lpdi;
LPDIRECTINPUTDEVICE m_keyboard;
unsigned char keystate[256];
void Init(void)
{
if (FAILED(DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION,
IID_IDirectInput8, (void**)&lpdi, NULL)))
{
// error code
}
if (FAILED(lpdi->CreateDevice(GUID_SysKeyboard, &m_keyboard, NULL)))
{ /* error code */ }
if (FAILED(m_keyboard->SetDataFormat(&c_dfDIKeyboard)))
{ /* error code */ }
if (FAILED(m_keyboard->SetCooperativeLevel(hWND, DISCL_BACKGROUND |
DISCL_NONEXCLUSIVE)))
{ /* error code */ }
if (FAILED(m_keyboard->Acquire()))
{ /* error code */ }
}
The first function starts DirectInput8. I'd be wasting your time explaining all the parameters because they will most likely stay the same.
The next four functions initiate and calibrate a DIRECTINPUTDEVICE, specifically your keyboard. Again, I won't explain the parameters because you will rarely ever change them. If you must know the billions of insignificant details, just look at the DX8 documentation (although it probably won't help, trust me on this one).
Now, let's get some input.
void Render(void)
{
if (FAILED(m_keyboard->GetDeviceState(sizeof(unsigned char[256]), (LPVOID)keystate)))
{ /* error code */ }
if (keystate[DIK_LCONTROL] & 0x80)
{
// shoot gun, jump, react somehow
}
}
#define KeyDown(data, n) ((data[n] & 0x80) ? true : false)
#define KeyUp(data, n) ((data[n] & 0x80) ? false : true)
if (KeyDown(keystate, DIK_LCONTROL))
{ /* do something */ }
void Destroy(void)
{
if (m_keyboard)
m_keyboard->Release();
if (lpdi)
lpdi->Release();
}
#define WIN32_LEAN_AND_MEAN
#include
#include
// Globals
LPDIRECTINPUT lpdi;
LPDIRECTINPUTDEVICE m_keyboard;
unsigned char keystate[256];
HWND hWND;
HINSTANCE g_hinstance;
bool done = false;
// Defines
#define KeyDown(data, n) ((data[n] & 0x80) ? true : false)
#define KeyUp(data, n) ((data[n] & 0x80) ? false : true)
// Function declarations
void Init(void);
void Render(void);
void Destroy(void);
// Message Loop CallBack Function
LRESULT CALLBACK WinProc ( HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam )
{
HDC hDC;
switch( iMsg )
{
// Called when window is first created
case WM_CREATE:
Init();
return( 0 );
// Called when the window is refreshed
case WM_PAINT:
hDC = BeginPaint(hWnd, &paintStruct);
EndPaint(hWnd, &paintStruct);
return( 0 );
// Called when the user closes the window or terminates the application
case WM_DESTROY:
Destroy();
PostQuitMessage( 0 );
return( 0 );
}
return DefWindowProc( hWnd, iMsg, wParam, lParam );
}
// Function to Create the Window and Display it
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
// basic windows creation stuff
while (!done)
{
PeekMessage(&msg, hWnd, NULL, NULL, PM_REMOVE);
if (msg.message == WM_QUIT) // do we receive a WM_QUIT message?
{
done = true; // if so, time to quit the application
}
else
{
Render();
TranslateMessage(&msg); // translate and dispatch to event queue
DispatchMessage(&msg);
}
}
return ( msg.wParam );
}
void Init(void)
{
if (FAILED(DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION,
IID_IDirectInput8, (void**)&lpdi, NULL)))
{
// error code
}
if (FAILED(lpdi->CreateDevice(GUID_SysKeyboard, &m_keyboard, NULL)))
{ /* error code */ }
if (FAILED(m_keyboard->SetDataFormat(&c_dfDIKeyboard)))
{ /* error code */ }
if (FAILED(m_keyboard->SetCooperativeLevel(hWND, DISCL_BACKGROUND |
DISCL_NONEXCLUSIVE)))
{ /* error code */ }
if (FAILED(m_keyboard->Acquire()))
{ /* error code */ }
}
void Render(void)
{
if (FAILED(m_keyboard->GetDeviceState(sizeof(unsigned char[256]), (LPVOID)keystate)))
{ /* error code */ }
if (KeyDown(keystate, DIK_ESCAPE))
{
PostQuitMessage(0);
}
}
void Destroy(void)
{
if (m_keyboard)
m_keyboard->Release();
if (lpdi)
lpdi->Release();
}
I've included the source code for a very easy to use wrapper system for DirectInput8. To use these in your game/application, all you need to do is call a few functions. The following is a pseudo program that uses the system.
// whole lot of stuff
// initiates the program
void Init(void)
{
// other important stuff
Init_CInput8(hWND); // takes handle to the window as parameter
Init_Keyboard(g_hinstance); // takes instance handle as parameter
Init_Mouse(g_hinstance); // takes instance handle as parameter
// other important stuff
}
// renders the program
void Render(void)
{
Read_Keyboard();
Read_Mouse();
// stuff
if (KeyDown(DIK_SPACE))
{
shooting = true;
}
if (KeyUp(DIK_SPACE))
{
shooting = false;
}
if (KeyPress(DIK_RETURN))
{
FireRockets(5);
}
// stuff
float mx, my;
Get_Mouse_Movement(mx, my);
cursor_x += mx;
cursor_y += my;
if (Button_Down(LEFT_BUTTON))
{
LaunchGrenade();
}
}
// de-initiates the program
void Destroy(void)
{
Release_Mouse();
Release_Keyboard();
Shutdown_CInput8();
}
For more information on using the mouse, see my follow-up article DirectX 8 and the Mouse.