其实我们是可以通过Windows消息和API取得键盘或者鼠标或者其他设备的输入信息,但这有个等待windows消息传送的延时,笔者试过直接在消息回调函数中相应键盘的上下左右消息去使场景中的模型进行旋转,感觉有明显的延时。这对于游戏玩家来说简直是噩梦,就好像我在玩lol,舍友都在用迅雷下AV一样的信息。而DirectX是直接与硬件进行交流,不需要去等待windows传送消息。DirectInput可以直接获得硬件的消息,立即响应。
要用DirectInput获得一个硬件设备的信息和初始化Direct3D一样要经过几个步骤:
1.创建DirectInput对象
2.创建设备对象
3.设定设备数据格式
4.设定程序协调层级
5.获得设备
6.取得设备状态
前面4步是初始化设备。
1.创建DirectInput对象
//DirectInput8对象
LPDIRECTINPUT8 pInputSystem;
//-1、创建DirectInput8对象
hr = DirectInput8Create( hInst, DIRECTINPUT_VERSION, IID_IDirectInput8,
(VOID**)&pInputSystem, NULL );
if( FAILED( hr ) )
{
MessageBox( NULL, L"DirectInput8Create()-FAILED!", NULL, MB_OK );
return false;
}
首先声明一个DirectInput对象指针,然后调用DirectInput8Create()方法创建DirectInput对象,最后判断是否创建成功。具体参数含义可以查阅MSDN.
2.创建设备对象
//键盘设备
LPDIRECTINPUTDEVICE8 pKeyboardDevice;
//-2、创建键盘DirectInput8Device
hr = pInputSystem->CreateDevice( GUID_SysKeyboard, &pKeyboardDevice, NULL );
if( FAILED(hr) )
{
MessageBox( NULL, L"pInputSystem->CreateDevice()-FAILED!", NULL, MB_OK );
return false;
}
首先声明一个设备指针,然后调用DirectInput对象的成员函数CreateDevice()创建设备,这个创建的是键盘设备,具体由CreateDevice()的第一个参数决定,对于鼠标应为:GUID_SysMouse.
3.设定设备数据格式
//-3、设置键盘的数据格式
hr = pKeyboardDevice->SetDataFormat( &c_dfDIKeyboard );
if( FAILED( hr ) )
{
MessageBox( NULL, L"pKeyboardDevice->SetDataFormat()-FAILED!", NULL, MB_OK );
return false;
}
由DirectInputDevice设备的SetDataFormat()成员函数完成,参数只有一个是一个关于数据格式的常量,对于鼠标有两种数据格式:c_dfDIMouse 、c_dfDIMouse2 用哪一个取决于先前声明的鼠标设备类型,但要保持前后一致。
4.设定程序协同层级
//-4、设置设备合作等级
hr = pKeyboardDevice->SetCooperativeLevel( _hWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE );
if( FAILED(hr) )
{
MessageBox( NULL, L"pKeyboardDevice->SetCooperativeLevel()-FAILED!", NULL, MB_OK );
return false;
}
所谓的协同层级就是手你的程序如何和其他程序共同使用此设备。相关参数:
DISL_BACKGROUND 程序当前非活跃,取得设备信息
DISL_EXCLUSIVE 独占模式,其他程序无法使用程序所建立与使用的输入装置,设置前应先检查当前设备的协同等级
DISL_FORCGROUND 程序只有在活跃时,才取得设备信息
DISL_NONEXCLUSIVE非独占模型,与其他程序共享设备
DISL_NOWINKEY 无法使用Windows键,防止使用者按下中断键导致程序结束
5.获取设备
//-5、获取设备
hr = pKeyboardDevice->Acquire();
if( FAILED(hr) )
{
MessageBox( NULL, L"pMouseDevice->Acquire()-FAILED!", NULL, MB_OK );
return false;
}
十分简单,调用设备的成员函数Acquire(), 检查是否获取成功。
6.取得设备状态
if( FAILED(pKeyboardDevice->GetDeviceState( sizeof(keysBuffer), (LPVOID)keysBuffer )) )
{
if( FAILED( pKeyboardDevice->Acquire() ) )
return false;
if( FAILED( pKeyboardDevice->GetDeviceState( sizeof(keysBuffer), (LPVOID)keysBuffer )) )
{
MessageBox( NULL, L" pKeyboardDevice->GetDeviceState()-FAILED!", NULL, MB_OK );
return false;
}
}
也非常简单,调用设备的GetDeviceState()成员函数,一般在获取状态失败一次后再请求一次设备,然后获取设备状态。
经过以上步骤就已经取得设备的当前状态,剩下的问题就是如何响应
一、对于键盘消息
char keyboardState[256];
//方向键上按下
if( keyboardState[DIK_UP] & 0x80)
//响应操作
//方向键右按下
if( keyboardState[DIK_RIGHT] & 0x80)
//响应操作
//方向键下按下
if( keyboardState[DIK_DOWN] & 0x80)
//响应操作
//方向键左按下
if( keyboardState[DIK_LEFT] & 0x80)
//响应操作
首先定义了一个256大小的数组作为输入缓冲区,代表键盘上256个键的状态,对于每一个键的状态是一个8bit的内存,高位代表键的状态。所以与(0x80)作And运算,如果不为0则代表此键被按下,反之未被按下。DIK_UP之类的是Direct的枚举类型。具体可查阅MSDN.
二、对于鼠标
对于鼠标在调用GetDeviceState()时需要在此函数的第二个参数传入一个类型为DIMOUSESTATE或DIMOUSESTATE2的结构体,以下是该结构体的定义
typedef struct DIMOUSESTATE {
LONG lX;
LONG lY;
LONG lZ;
BYTE rgbButtons[4];
} DIMOUSESTATE, *LPDIMOUSESTATE;
两个结构的的区别只在于最后一项rgbButtons[]的大小有所不同。当我们要响应鼠标消息时要利用到rgbButtons[]数组,rgbButtons[0]代表鼠标左键的状态,rgbButtons[1]代表鼠标右键的状态,同样采用 and (0x80)的方法判断键的状态。
三、对于游戏控制器,手柄呀什么的判断哪个键是否被按下的方法还是一样只是取得的状态保存的结构不一样,具体这里不想说,可以查阅MSDN.
一个封装后的DirectInput类,支持响应鼠标和键盘输入。
/********************************************************************
* 游戏输入类 *
* file: CLDirectInput.h *
* copyright (C) 2013 by CoderLing *
* email : coderling@gmail.com *
* blog: http://blog.csdn.net/coderling *
********************************************************************/#ifndef CLDIRECTINPUT_H
#define CLDIRECTINPUT_H
#define DEBUG
#define DIM_LEFT 0
#define DIM_RIGHT 1
#define DIRECTINPUT_VERSION 0x0800
#define KEY_SIZE 256 //键盘数据大小#include <dinput.h>struct POINT3
{int x, y, z;POINT3( int _x, int _y, int _z){x = _x; y = _y; z = _z;}
};class CLDirectInput
{//---------------------------------------------//-1.处理键盘消息//----上下左右,字符消息//-2.处理鼠标消息//----鼠标左右键,中建//---------------------------------------------public:CLDirectInput();~CLDirectInput();
public://初始化directInputbool Initialize( HWND, HINSTANCE ); //更新设备当前状态bool UpdateDevices();//响应应键盘消息bool IsKeyDown( unsigned int );bool IsKeyUp( unsigned int );//响应鼠标消息bool IsMouseButtonDown( unsigned int );bool IsMouseButtonUp( unsigned int );long GetMouseWheelDir();POINT GetMousePos();POINT GetMousePosRel();
protected://由析构函数调用,释放资源void ShutDown();//DirectInput8对象LPDIRECTINPUT8 pInputSystem;//键盘设备LPDIRECTINPUTDEVICE8 pKeyboardDevice;char keysBuffer[KEY_SIZE];char keysBufferOld[KEY_SIZE];//鼠标设备LPDIRECTINPUTDEVICE8 pMouseDevice;DIMOUSESTATE mouseState;DIMOUSESTATE mouseStateOld;//鼠标位置信息,为移动量long xMousePos;long yMousePos;private:};#endif/********************************************************************
* 游戏输入类 *
* file: CLDirectInput.cpp *
* copyright (C) 2013 by CoderLing *
* email : coderling@gmail.com *
* blog: http://blog.csdn.net/coderling *
********************************************************************/
#include "stdafx.h"
#include "LDirectInput.h"
#include <Windows.h>
#include <iostream>
#include <fstream>
#pragma comment(lib, "dinput8.lib")
#pragma comment(lib, "DXGuid.lib")
//g构造函数
CLDirectInput::CLDirectInput():pInputSystem( NULL ), pKeyboardDevice( NULL ),pMouseDevice( NULL ), xMousePos( 0 ), yMousePos( 0 )
{memset( keysBuffer, 0, sizeof(char)*KEY_SIZE );memset( keysBufferOld, 0, sizeof(char)*KEY_SIZE );memset( &mouseState, 0, sizeof( mouseState ) );memset( &mouseStateOld, 0, sizeof( mouseStateOld ) );
}//析构函数
CLDirectInput::~CLDirectInput()
{ShutDown();
}//---------------------------------------------
//-name: Initialize()
//初始化DirectInput
//-1、创建DirectInput8对象
//-2、创建DirectInputDevice设备
//-3、设置设备数据格式,取决于何种设别
//-4、设置设备合作等级
//----------------------------------------------
bool CLDirectInput::Initialize(HWND hWnd, HINSTANCE hInst)
{HRESULT hr;HWND _hWnd = hWnd;//-1、创建DirectInput8对象hr = DirectInput8Create( hInst, DIRECTINPUT_VERSION, IID_IDirectInput8, (VOID**)&pInputSystem, NULL );if( FAILED( hr ) ){MessageBox( NULL, L"DirectInput8Create()-FAILED!", NULL, MB_OK );return false;}//---------键盘初始化---------------begin////-2、创建键盘DirectInput8Devicehr = pInputSystem->CreateDevice( GUID_SysKeyboard, &pKeyboardDevice, NULL );if( FAILED(hr) ){MessageBox( NULL, L"pInputSystem->CreateDevice()-FAILED!", NULL, MB_OK );return false;}//-3、设置键盘的数据格式hr = pKeyboardDevice->SetDataFormat( &c_dfDIKeyboard );if( FAILED( hr ) ){MessageBox( NULL, L"pKeyboardDevice->SetDataFormat()-FAILED!", NULL, MB_OK );return false;}//-4、设置设备合作等级hr = pKeyboardDevice->SetCooperativeLevel( _hWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE );if( FAILED(hr) ){MessageBox( NULL, L"pKeyboardDevice->SetCooperativeLevel()-FAILED!", NULL, MB_OK );return false;}//清空缓冲区memset( keysBuffer, 0, sizeof(char)*KEY_SIZE );//------键盘初始化----------end////------鼠标初始化----------begin////-2、创建鼠标设备hr = pInputSystem->CreateDevice( GUID_SysMouse, &pMouseDevice, NULL );if( FAILED(hr) ){MessageBox( NULL, L"pInputSystem->CreateDevice()-FAILED!", NULL, MB_OK );return false;}//-3、设置鼠标数据格式hr = pMouseDevice->SetDataFormat( &c_dfDIMouse );if( FAILED(hr) ){MessageBox( NULL, L"pMouseDevice->SetDataFormat()-FAILED!", NULL, MB_OK );return false;}//-4、设置设备合作等级hr = pMouseDevice->SetCooperativeLevel( _hWnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE );if( FAILED(hr) ){MessageBox( NULL, L"pMouseDevice->SetCooperativeLevel()-FAILED!", NULL, MB_OK );return false;}//-----鼠标初始化--------end//return true;
}//----------------------------------------------
//-name:UpdateDevice()
//-更新设备状态
//-GetDeviceState()
//----------------------------------------------
bool CLDirectInput::UpdateDevices()
{HRESULT hr;//-更新鼠标信息if( pMouseDevice ){//-5、获取设备hr = pMouseDevice->Acquire();if( FAILED(hr) ){MessageBox( NULL, L"pMouseDevice->Acquire()-FAILED!", NULL, MB_OK );return false;}memcpy( &mouseStateOld, &mouseState, sizeof(mouseState) );if( FAILED(pMouseDevice->GetDeviceState( sizeof(DIMOUSESTATE), (LPVOID)&mouseState )) ){if( FAILED(pMouseDevice->Acquire()) )return false;if( FAILED(pMouseDevice->GetDeviceState( sizeof(DIMOUSESTATE), (LPVOID)&mouseState )) ){MessageBox( NULL, L"pMouseDevice->GetDeviceState()-FAILED!", NULL, MB_OK );return false;}}xMousePos += mouseState.lX;yMousePos += mouseState.lY;}//-更新键盘信息if( pKeyboardDevice ){//-5、获取设备hr = pKeyboardDevice->Acquire();if( FAILED(hr) ){MessageBox( NULL, L"pKeyboardDevice->Acquire()-FAILED!", NULL, MB_OK );return false;}//保留信息用于比较memcpy( keysBufferOld, keysBuffer, sizeof(char)*KEY_SIZE );if( FAILED(pKeyboardDevice->GetDeviceState( sizeof(keysBuffer), (LPVOID)keysBuffer )) ){if( FAILED( pKeyboardDevice->Acquire() ) )return false;if( FAILED( pKeyboardDevice->GetDeviceState( sizeof(keysBuffer), (LPVOID)keysBuffer )) ){MessageBox( NULL, L" pKeyboardDevice->GetDeviceState()-FAILED!", NULL, MB_OK );return false;}}}
#ifndef DEBUGstd::ofstream out;out.open("text.txt");for(int i = 0;i < 256;i++){if(keysBuffer[i] != 0)out<<"dfadf"<<' ';}out<<std::endl <<std::endl;out.close();
#endifreturn true;
}//----------------------------------------------
//-name:IsKyeDown()
//-判断键盘是否有键被按下
//----------------------------------------------
bool CLDirectInput::IsKeyDown( unsigned int keyNum )
{return keysBuffer[keyNum] & 0x80;
}//----------------------------------------------
//-name:IsKeyUp()
//-判断键盘的键是否处于一般状态
//----------------------------------------------
bool CLDirectInput::IsKeyUp( unsigned int keyNum )
{//-如果此键没被按下,而且之前被按下return !(keysBuffer[keyNum] & 0x80) && (keysBuffer[keyNum] != keysBufferOld[keyNum]);
}//----------------------------------------
//-name:IsMouseButtonDown()
//-判断鼠标是否被按下
//----------------------------------------
bool CLDirectInput::IsMouseButtonDown( unsigned int buttonId )
{return mouseState.rgbButtons[buttonId] & 0x80;
}//---------------------------------------
//-name:IsMouseButtonUp()
//-判断按下的某键是否松开
//---------------------------------------
bool CLDirectInput::IsMouseButtonUp( unsigned int buttonId )
{return !(mouseState.rgbButtons[buttonId] & 0x80) &&(mouseState.rgbButtons[buttonId] != mouseStateOld.rgbButtons[buttonId]);
}//----------------------------------------
//-GetMouseRelative()
//-返回鼠标滚轮滚动方向,true代表向前
//----------------------------------------
long CLDirectInput::GetMouseWheelDir()
{return mouseState.lZ;
}//------------------------------------------
//-GetMousePos()
//-返回鼠标坐标
//-------------------------------------------
POINT CLDirectInput::GetMousePos()
{POINT pos;pos.x = xMousePos;pos.y = yMousePos;return pos;
}POINT CLDirectInput::GetMousePosRel()
{POINT rel;rel.x = mouseState.lX;rel.y = mouseState.lY;return rel;
}
//------------------------------------------
//-name:ShutDown()
//-释放相应资源
//------------------------------------------
void CLDirectInput::ShutDown()
{if (pInputSystem){pInputSystem->Release();pInputSystem = NULL;}if (pKeyboardDevice){pKeyboardDevice->Unacquire();pKeyboardDevice->Release();pKeyboardDevice = NULL;}if (pMouseDevice){pMouseDevice->Unacquire();pMouseDevice->Release();pMouseDevice = NULL;}
}