Direct3D轮回:构建基于DirectInput机制的鼠标输入设备

键盘、鼠标、游戏杆是最为常用的游戏输入设备。

Xna直接向客户提供了对于以上输入设备的支持。例如,我们可以直接使用

MouseState mouseState = Mouse.GetState();

获取鼠标输入设备的当前状态,从而进一步检测各个键位的当前状态。Keyboard、GamePad用法与Mouse类似,在此不再赘述。

回到Direct3D环境中。因为工程本身基于Win32App,所以我们可以获得窗口消息的支持,从而检测鼠标和键盘的当前状态。不过,处于效率考虑,这里推荐大家使用更加高效的机制——DirectInput。

下面我们构建基于DirectInput机制的鼠标输入设备。

1.在前篇工程基础上新建CD3DInput类;

 

/* -------------------------------------

代码清单:D3DInput.h
来自:
http://www.cnblogs.com/kenkao

-------------------------------------
*/

#include 
" D3DInit.h "
#include 
< dinput.h >
#pragma  comment(lib, "dinput8.lib")

#define  BUTTONSTATE_PRESSED  0x01
#define  BUTTONSTATE_RELEASED 0x00

#pragma  once

class  CMouseInput
{
public :
    CMouseInput();
    
~ CMouseInput();
    HRESULT Initialize(HINSTANCE hInst,HWND hWnd);      
// 初始化输入设备
     void     GetState();                                  // 获取设备状态
    DWORD   LeftButton();                                // 鼠标左键状态
    DWORD   MiddleButton();                              // 鼠标滚轮状态
    DWORD   RightButton();                               // 鼠标右键状态
     void     Release();                                   // 释放输入设备
     long     MouseMoveX();                                // 鼠标X方向偏移
     long     MouseMoveY();                                // 鼠标Y方向偏移
     void     SetPosition(POINT point);                    // 设置鼠标位置
     void     GetPosition(POINT &  point);                   // 获取鼠标位置
    LONG    GetWheelLenth();                             // 获取滚轮滚动的距离
private :
    HWND                 m_hWnd;                           
// 设备所属的窗口句柄
    LPDIRECTINPUT8       m_pIDirectInput;                   // IDirectInput接口对象
    LPDIRECTINPUTDEVICE8 m_pIDirectInputDevice;             // IDirectInput设备对象
    DIMOUSESTATE         m_mouseState;                      // 鼠标状态结构体
};

 

Direct3D轮回:构建基于DirectInput机制的鼠标输入设备 D3DInput.cpp
/* -------------------------------------

代码清单:D3DInput.cpp
来自:
http://www.cnblogs.com/kenkao

-------------------------------------
*/


#include 
" StdAfx.h "
#include 
" D3DInput.h "

CMouseInput::CMouseInput() : m_pIDirectInput(NULL),
                             m_pIDirectInputDevice(NULL)
{

}

CMouseInput::
~ CMouseInput()
{

}

HRESULT CMouseInput::Initialize(HINSTANCE hInst,HWND hWnd)
{
    m_hWnd 
=  hWnd;
    HRESULT hr;
    
// 创建IDirectInput接口对象
    hr = DirectInput8Create(hInst,DIRECTINPUT_VERSION,IID_IDirectInput8,( void ** ) & m_pIDirectInput,NULL);
    
if (FAILED(hr)){
        
return  hr;
    }
    
// 初始化鼠标输入设备
    hr = m_pIDirectInput -> CreateDevice(GUID_SysMouse, & m_pIDirectInputDevice,NULL); // GUID_SysMouse代表初始化设备为鼠标设备
     if (FAILED(hr)){
        ReleaseCOM(m_pIDirectInput);
        
return  hr;
    }
    
// 设置鼠标设备的数据格式
    hr = m_pIDirectInputDevice -> SetDataFormat( & c_dfDIMouse);
    
if (FAILED(hr)){
        ReleaseCOM(m_pIDirectInputDevice);
        ReleaseCOM(m_pIDirectInput);
        
return  hr;
    }
    
// 设置鼠标设备的协调级别
    hr = m_pIDirectInputDevice -> SetCooperativeLevel(hWnd,DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
    
if (FAILED(hr)){
        ReleaseCOM(m_pIDirectInputDevice);
        ReleaseCOM(m_pIDirectInput);
        
return  hr;
    }
    
// 获取鼠标设备访问权限
    hr = m_pIDirectInputDevice -> Acquire();
    
return  S_OK;
}

void  CMouseInput::GetState()
{
    HRESULT hr;
    DWORD dwReadNum 
=   1 ;
    hr 
=  m_pIDirectInputDevice -> GetDeviceState( sizeof (m_mouseState),(LPVOID) & m_mouseState);
    
if (FAILED(hr)){
        hr 
=  m_pIDirectInputDevice -> Acquire();
    }
}

DWORD CMouseInput::LeftButton()
{
    
if (m_mouseState.rgbButtons[ 0 &   0x80 )
    {
        
return  BUTTONSTATE_PRESSED;
    }
    
else
        
return  BUTTONSTATE_RELEASED;
}

DWORD CMouseInput::MiddleButton()
{
    
if (m_mouseState.rgbButtons[ 2 &   0x80 )
    {
        
return  BUTTONSTATE_PRESSED;
    }
    
else
        
return  BUTTONSTATE_RELEASED;
}

DWORD CMouseInput::RightButton()
{
    
if (m_mouseState.rgbButtons[ 1 &   0x80 )
    {
        
return  BUTTONSTATE_PRESSED;
    }
    
else
        
return  BUTTONSTATE_RELEASED;
}

void  CMouseInput::Release()
{
    
// 释放鼠标设备访问权限
    m_pIDirectInputDevice -> Unacquire();
    ReleaseCOM(m_pIDirectInputDevice);
    ReleaseCOM(m_pIDirectInput);
}

void  CMouseInput::SetPosition(POINT point)
{
    ScreenToClient(m_hWnd,
& point);
    SetCursorPos(point.x,point.y);
}

void  CMouseInput::GetPosition(POINT &  point)
{
    GetCursorPos(
& point);
    ScreenToClient(m_hWnd,
& point);
}

LONG CMouseInput::GetWheelLenth()
{
    
return  m_mouseState.lZ;
}

虽然构建的类名为CD3DInput,不过我实际写入的类名是CMouseInput,后续可能会把键盘和游戏杆输入设备的构建也放到这两个文件里,引用起来比较方便。

默认情况下,DirectInput设备以立即模式获取输入信息,意味着数据读取的前一刻,输入信息不会被DirectInput记录。

与立即模式相对的是缓冲模式,输入信息将被放在一个缓冲区内,供DirectInput设备读取。

这里我们运用立即模式构建鼠标输入设备。

通过GetDeviceState函数,我们将当前的鼠标设备状态获取到名为DIMOUSESTATE的结构体中。关于这个结构体的定义,大家可以看下SDK的说明文档,很好理解~

完成各个键位的检测之后,便可在前篇工程的代码基础上加入鼠标输入设备的单元测试代码。

2.丰富D3DGame.cpp的代码内容;

Direct3D轮回:构建基于DirectInput机制的鼠标输入设备 D3DGame.cpp
/* -------------------------------------

代码清单:D3DGame.cpp
来自:
http://www.cnblogs.com/kenkao

-------------------------------------
*/

#include 
" StdAfx.h "
#include 
" D3DGame.h "
#include 
< stdio.h >

HINSTANCE g_hInst;
HWND g_hWnd;
IDirect3D9       
* g_pD3D         =  NULL;
IDirect3DDevice9 
* g_pD3DDevice   =  NULL;
CMouseInput      
* g_pMouseInput  =  NULL;

//  鼠标输入单元测试函数
void  TestMouseInput();

void  Initialize(HINSTANCE hInst, HWND hWnd)
{
    g_hInst 
=  hInst;
    g_hWnd  
=  hWnd;
    InitD3D(
& g_pD3D,  & g_pD3DDevice, hWnd);
    g_pMouseInput 
=   new  CMouseInput;
    g_pMouseInput
-> Initialize(hInst,hWnd);
}

void  LoadContent()
{
    
}

void  Update()
{
    TestMouseInput();
}

void  Draw()
{
    g_pD3DDevice
-> Clear( 0 , NULL, D3DCLEAR_TARGET  |  D3DCLEAR_ZBUFFER, D3DCOLOR_RGBA( 100 , 149 , 237 , 255 ),  1.0f 0 );
    
if (SUCCEEDED(g_pD3DDevice -> BeginScene())) 
    {
        g_pD3DDevice
-> EndScene();
    }
    g_pD3DDevice
-> Present(NULL, NULL, NULL, NULL);
}

void  UnloadContent()
{

}

void  Dispose()
{
    ReleaseCOM(g_pMouseInput);
    ReleaseCOM(g_pD3DDevice);
    ReleaseCOM(g_pD3D);
}

void  TestMouseInput()
{
    POINT point;
    g_pMouseInput
-> GetState();
    g_pMouseInput
-> GetPosition(point);
    TCHAR tmpText[
50 ];
    
if (g_pMouseInput -> LeftButton() == BUTTONSTATE_PRESSED)
    {
        sprintf(tmpText,
" 鼠标左键已按下,X-Y坐标为(%d,%d) " ,point.x,point.y);
        MessageBox(NULL,tmpText,
" 提示 " ,MB_OK | MB_ICONINFORMATION);
    }
    
else   if (g_pMouseInput -> MiddleButton() == BUTTONSTATE_PRESSED)
    {
        sprintf(tmpText,
" 鼠标滚轮已按下,X-Y坐标为(%d,%d) " ,point.x,point.y);
        MessageBox(NULL,tmpText,
" 提示 " ,MB_OK | MB_ICONINFORMATION);
    }
    
else   if (g_pMouseInput -> RightButton() == BUTTONSTATE_PRESSED)
    {
        sprintf(tmpText,
" 鼠标右键已按下,X-Y坐标为(%d,%d) " ,point.x,point.y);
        MessageBox(NULL,tmpText,
" 提示 " ,MB_OK | MB_ICONINFORMATION);
    }
}

我们为Initialize新增一个HINSTANCE hInst参数,这个参数在初始化鼠标输入设备时要用到,之后,通过

g_pMouseInput = new CMouseInput;
g_pMouseInput->Initialize(hInst,hWnd);

来完成鼠标输入设备的声明及初始化。

我们在Update函数中调用鼠标输入单元检测函数TestMouseInput。该函数中,首先要通过

g_pMouseInput->GetState();

获取当前的设备状态,其实也就是输入信息的读取。之后便可对鼠标各个键位状态进行检测。

当然,最后不要忘记在Dispose函数中调用

ReleaseCOM(g_pMouseInput);//联动调用CMouseInput::Release()函数

将我们构建的鼠标输入设备释放掉~ 这是C++环境,GC的工作只能我们自己完成咯 ^ ^

如下为效果图:

Direct3D轮回:构建基于DirectInput机制的鼠标输入设备

回到最初,我们之所以认为DirectInput是一种更加高效的机制,是因其基于硬件驱动实现。

感兴趣的朋友不妨做个实验:

在 开始--->控制面板--->鼠标 中更换左右键功能,DirectInput设备不受影响,因为控制面板里的设置是基于软件实现的~

Good Luck~

 

你可能感兴趣的:(input)