• 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;                     //鼠标状态结构体
    };
    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的代码内容;

    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.0f0);
        
    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的工作只能我们自己完成咯 ^ ^

    如下为效果图:

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

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

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

    Good Luck~

  • 相关阅读:
    解决方案 git@github.com出现Permission denied (publickey)
    github设置添加SSH
    base64是啥原理
    PHP面试题:HTTP中POST、GET、PUT、DELETE方式的区别
    PHP中put和post区别
    常用的微信编辑器
    局域网内一台电脑的ip地址自己会变,怎样让它不变
    Trendalyzer is an information visualization software
    FineReport报表和水晶报表的比较
    x
  • 原文地址:https://www.cnblogs.com/kenkao/p/2087111.html
Copyright © 2020-2023  润新知