【Direct3D游戏开发】——DirectInput 让世界动起来

   其实我们是可以通过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:
	//初始化directInput
	bool 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 "CLDirectInput.h"
#include <Windows.h>
#include <iostream>
#include <fstream>

//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、创建键盘DirectInput8Device
	hr = 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 DEBUG
	std::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();
#endif
	return 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;
	}
}

           

          今天写的一个输入DEMO,其实主要为了学习Direct3D的字体,然后就顺便把input类完善了下,并应用在上面。传送门

             The End~~~~~~~~~~~~

          昨天WG说他在琴房遇到了一个漂亮的师妹,长的像loli一般,回来和我说太久没经过妹子了,紧张的一B。然后我在想真是青春啊,然后又想到的是,IT男呀,推得了方程式,推不倒妹子,唉o(╯□╰)o

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值