- 创建IDirectInput8接口,它提供对整个DirectInput的支持。
LPDIRECTINPUT8 lpdi;
DirectInput8Create(main_instance, DIRECTINPUT_VERSION, IID_IDirectInput8, (LPVOID*)&lpdi, NULL); - 查询设备的GUID。这一步基本上只对于JoyStick之类需要调用,特殊的如果有多个鼠标也需要调用,一般对于键盘和鼠标不需要,因为有全局定义的默认键盘鼠标的GUID:GUID_SysKeyboard和GUID_SysMouse(需要#define INITGUID, #include <OBJBASE.H>或者连上DXGUID.LIB)。
- 调用CreateDevice方法来创建一个设备。
IDIRECTINPUTDEVICE8 lpdikey;
lpdi->CreateDevice(GUID_SysKeyboard, &lpdikey, NULL); - 对于你创建的设备设置协作等级。
lpdikey->SetCooperativeLevel(main_window_handle, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE);这两个是常用的属性,表示程序在后台可以使用设备并且非独占使用。如果有另外一个独占/前台运行的程序,那么这个调用就会失败。 - 设置数据格式。这里设置了什么数据格式,在最后查询的时候就用相应的数据结构。对于键盘,数据格式为256个元素的UCHAR的数组,对于其他设备则有相应的数据结构(DIMOUSESTATE, DIJOYSTATE, DIJOYSTATE2)
lpdikey->SetDataFormat(&c_dfDIKeyboard);
c_dfDIKeyboard, c_dfDIMouse, c_dfDIJoystick, c_dfDIJoystick2为预定义的DIDATAFORMAT结构。 - 设置设备的性能。这个步骤一般不用,即使对于复杂的JoyStick也只是需要设置其中的很少部分。因为这个调用相当可怕。
- 获得设备。
lpdikey->Acquire(); - 轮询设备。
lpdikey->Poll(); - 从设备获得数据。这是我们真正需要的。以上的一切都是为了这个。
UCHAR keystate[256];
lpdikey->GetDeviceState(sizeof(keystate), (LPVOID)keystate);
然后就可以对每个数组元素进行查询,来确定按键的情况。(&0x80 != 0 表示按下)DirectInput中对于虚拟键的定义以DIK_开头。 - 最后,说一下释放设备的过程。
lpdikey->Unacquire();
lpdikey->Release();
lpdi->Release();
以上这些步骤就是对于最简单的设备——键盘的使用。不过其他的设备和他也并没有差开多少。只是Joystick在开始的时候需要用回调函数和枚举的方法来获取GUID,然后就可以顺着下面的步骤做下来。
下面还有另外一个问题:在DirectInput工作过程中输入设备很可能发生各种各样的意外。比如你不小心拉掉了手柄线。这个时候你可以检测并且重新获取设备。利用GetDeviceState函数的返回值我们可以知道设备的情况。如下是GetDeviceState()可能返回的错误代码:
- DIERR_INPUTLOST 设备已经丢失。
- DIERR_INVALIDPARAM 函数的参数无效
- DIERR_NOTACQUIRED 已经完全失去设备
- DIERR_NOTINITIALIZED 设备没有准备好
- E_PENDING 数据还未准备好
所以如果出现了DIERR_INPUTLOST的错误,我们可以尝试重新获取设备。一般来说对于键盘丢失的几率几乎为零,多数时候,你只会丢失Joystick。
下面说一下对于Mouse 和 Joystick的不同之处。
Mouse的数据输入默认的为相对模式,也就是每次读入的为相对于上一次位置数据的相对值(偏移值)。对于DIMOUSESTATE结构中的rgbButtons数组,0,1,2下标分别表示左键,右键,中键。
对于游戏杆,我真是不想说了。因为在CreateDevice前为了得到GUID实在是有太多的要说了。调用枚举函数EnumDevices(),设置回调函数,记录下回调函数中传入的设备GUID和其他一些信息。说起来真怕自己说不清楚,还是直接给出一个例子,这样好理解一些。
其实就是在CreateDevice前多做了一些事:
char joyname[256];
GUID joystickGUID;
lpdi->EnumDevices(DIDEVTYPE_JOYSTICK, DInput_Enum_Joysticks, &joystickGUID, DIEDFL_ATTACHEDONLY); // 枚举所有Joystick,必须是接上的Joystick,回调函数为DInput_Enum_Joystick。
回调函数的格式为:BOOL CALLBACK DInput_Enum_Joystick(LPCDIDEVICEINSTANCE lpdidi, LPVOID lpParam);
在回调函数中我们可以利用其中的LPCDIDEVCEINSTANCE结构参数中的设备的信息来创建自己需要的记录(主要保存下查询到的GUID,因为有了GUID下面的步骤就都见过了)
Joystick的另外一个特殊的地方就是需要设置一下设备性能SetProperty()。这就牵涉到一个非常复杂的结构DIPROPRANGE,这一块只能参阅DirectX SDK文档了,这里是肯定说不明白的。听说加起来有10页……不过一般情况下只要设置一下轴的范围和DeadZone。