其实我们是可以通过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; }
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; } }
经过以上步骤就已经取得设备的当前状态,剩下的问题就是如何响应
一、对于键盘消息
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;
三、对于游戏控制器,手柄呀什么的判断哪个键是否被按下的方法还是一样只是取得的状态保存的结构不一样,具体这里不想说,可以查阅MSDN.
一个封装后的DirectInput类,支持响应鼠标和键盘输入。
/******************************************************************** * 游戏输入类 * * file: CLDirectInput.h * * copyright (C) 2013 by CoderLing * * email : [email protected] * * 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 : [email protected] * * 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