首页 | 社区 | 博客 | 招聘 | 文章 | 新闻 | 下载 | 读书 | 代码
亲,您未登录哦! 登录 | 注册

DirectInput 鼠标编程入门

打印文章

分享到:
    前回同大家简单介绍了如何用 DirectInput 来进行键盘编程,本回所要讲述的就该是关于如何使用DirectInp
ut 来对另一个非常重要的输入设备----鼠标的编程问题。
  鼠标的编程同键盘编程的过程是非常相似的,有了上次的基础,你很快就能看出两者在形式上其实完全是大同
小异的.

1、DIRECTINPUT 的初始化
  同前面讲键盘编程的过程一样,我们还是先从 DIRECTINPUT 的初始化开始吧:
  #include <dinput.h>

  #define DINPUT_BUFFERSIZE 16

  LPDIRECTINPUT lpDirectInput; // DirectInput object
  LPDIRECTINPUTDEVICE lpMouse; // DirectInput device

  BOOL InitDInput(HWND hWnd)
  {
    HRESULT hr;

    // 创建一个 DIRECTINPUT 对象
    hr = DirectInputCreate(hInstanceCopy, DIRECTINPUT_VERSION, &lpDirectInput, NULL);

    if FAILED(hr)
    {
     // 失败
     return FALSE;
    }

    // 创建一个 DIRECTINPUTDEVICE 界面
    hr = lpDirectInput->CreateDevice(GUID_SysMouse, &lpMouse, NULL);
    if FAILED(hr)
    {
     // 失败
     return FALSE;
    }

    // 设定查询鼠标状态的返回数据格式
    hr = lpMouse->SetDataFormat(&c_dfDIMouse);
    if FAILED(hr)
    {
     // 失败
     return FALSE;
    }

    // 设定协作模式
    hr = lpMouse->SetCooperativeLevel(hWnd,
       DISCL_EXCLUSIVE | DISCL_FOREGROUND);
    if FAILED(hr)
    {
     // 失败
     return FALSE;
    }

    // 设定缓冲区大小
    // 如果不设定,缓冲区大小默认值为 0,程序就只能按立即模式工作
    // 如果要用缓冲模式工作,必须使缓冲区大小超过 0
    DIPROPDWORD property;

    property.diph.dwSize = sizeof(DIPROPDWORD);
    property.diph.dwHeaderSize = sizeof(DIPROPHEADER);
    property.diph.dwObj = 0;
    property.diph.dwHow = DIPH_DEVICE;
    property.dwData = DINPUT_BUFFERSIZE;

    hr = lpMouse->SetProperty(DIPROP_BUFFERSIZE, &property.diph);

    if FAILED(hr)
    {
     // 失败
     return FALSE;
    }

    hr = lpMouse->Acquire();
    if FAILED(hr)
    {
     // 失败
     return FALSE;
    }

  return TRUE;
  }
  除了少数几处改动以外,这段代码同前面讲的键盘编程的代码基本上完全一样。
  注意调用 CreateDevice 来建立一个 DIRECTINPUTDEVICE 界面时,我们用的参数是 GUID_SysMouse 而不是 G
UID_SysKeyboard,我们以此来指明了建立的是鼠标对象。相应的,在用 SetDataFormat 来设定返回数据的格式时
,我们用的参数是 &c_dfDIMouse 而不是 &c_dfDIKeyboard。
  还有要特别注意的是,前面讲到的键盘,在设置协作方式时,是只能按非独占方式工作的,而鼠标即可以按非
独占方式工作,也可以按独占方式工作。

2、DIRECTINPUT 的数据查询
  在作 DIRECTINPUT 的鼠标数据查询时, 我一般都是使用的缓冲模式而不是立即模式。原因很简单,因为鼠标
移动事件的频率很高, 按立即模式去处理就很难保证不丢失数据。至于 DIRECTX SDK 里的例程使用立即模式读取
数据则是因为它们用了一个多媒体计时器来保证以每秒三十次的频率处理接受鼠标数据。
  明白这一点后, 下面我们就来看看相应的代码。由于 DIRECTX SDK 里的例程有立即模式的代码,我就偷点懒
,下面只给出了一段缓冲模式下的代码:
  HRESULT UpdateInputState(void)
  {
    DWORD i;

    if(lpMouse != NULL)
    {
     DIDEVICEOBJECTDATA didod; // Receives buffered data
     DWORD dwElements;
     HRESULT hr;

     while(TRUE)
     {
      dwElements = 1; // 每次从缓冲区中读一个数据
      hr = lpMouse->GetDeviceData(sizeof(DIDEVICEOBJECTDATA),&didod,&dwElements,0);

      if FAILED(hr)
      {
       // 发生了一个错误
       if(hr == DIERR_INPUTLOST)
       {
        hr = lpMouse->Acquire(); // 试图重新取回设备
        if FAILED(hr)
        {
         return S_FALSE; // 失败
        }
       }
      }
      else
      if(elements == 1)
      {
       switch(didod.dwOfs)
       {
        case DIMOFS_X: // X 轴偏移量
                // didod.dwData 里是具体偏移相对值,单位为像素
          break;
        case DIMOFS_Y: // Y 轴偏移量
                // didod.dwData 里是具体偏移相对值,单位为像素
          break;
        case DIMOFS_BUTTON0: // 0 号键(左键)状态
                   // didod.dwData 里是具体状态值
                   // 低字节最高位为 1 则表示按下
                   // 低字节最高位为 0 表示未按下
          break;
        case DIMOFS_BUTTON1: // 1 号键(右键)状态
                   // 同上
          break;
        case DIMOFS_BUTTON2: // 2 号键(中键)状态
                   // 同上
          break;
        case DIMOFS_BUTTON3: // 3 号键状态
                   // 同上
          break;
       }
      }
      else if (elements == 0) break; // 缓冲区读空
     }
   }

  return S_OK;
  }
  这段代码注释得非常详细,相信你很快就能看懂。

3、DIRECTINPUT 的结束处理
  还记得当程序结束时必须要进行的释放处理吧,其代码如下:
  void ReleaseDInput(void)
  {
   if (lpDirectInput)
   {
    if(lpMouse)
    {
     // Always unacquire the device before calling Release().
     lpMouse->Unacquire();
     lpMouse->Release();
     lpMouse = NULL;
    }
    lpDirectInput->Release();
    lpDirectInput = NULL;
   }
  }

本栏文章均来自于互联网,版权归原作者和各发布网站所有,本站收集这些文章仅供学习参考之用。任何人都不能将这些文章用于商业或者其他目的。( Pfan.cn )

编程爱好者论坛

本栏最新文章