本系列文章由 net_assassin 整理编写,转载请注明出处。
http://blog.csdn.net/net_assassin/article/category/1100363
作者:net_assassin 邮箱: net_assassin@hotmail.com 期待着与志同道合的朋友们相互交流
这一章我们将学习如何使用DirectInput进行键盘和鼠标编程,从而为游戏提供对最常见的输入设备的支持。
键盘输入
键盘是所有游戏的标准输入设备,甚至是那些并不特别适用键盘的游戏的标准输入,所以游戏或多或少会使用键盘是个事实。
那么使用DirectInput比使用标准的API调用有什么优势呢?
1. Win32 API不是为游戏或者速度而设计的
2. Win32最多只能支持那种简单的摇杆,如果是复杂的摇杆,比如那种带几个轴的,8到10个按钮的等等,Win32就支持不了了。
3. 对鼠标的支持被限制在3个按钮,2个轴,一个滚轮。但是今天的市场上,很多鼠标有4个,5个按钮,甚至更多。
4. Win32对键盘的支持,主要是被设计用来支持键盘输入应用程序的。它有很多可以自动处理重复的键,可以把键码转换成ASCII字符等的功能,但是这些功能,游戏都不需要,而且,这会导致更宝贵的处理器循环的浪费。
5. Win32键盘处理代码虽然可以为你捕获一些键(比如Alt),但是这需要特殊的消息处理,才能够得到正确的操作。
6. 消息处理不是这个世界上最快的事情。应用程序得到了很多所需的鼠标消息,但是你必须等到这些消息队列空了以后才能够渲染桢,这将导致整个应用程序变慢。
1. Win32 API不是为游戏或者速度而设计的
2. Win32最多只能支持那种简单的摇杆,如果是复杂的摇杆,比如那种带几个轴的,8到10个按钮的等等,Win32就支持不了了。
3. 对鼠标的支持被限制在3个按钮,2个轴,一个滚轮。但是今天的市场上,很多鼠标有4个,5个按钮,甚至更多。
4. Win32对键盘的支持,主要是被设计用来支持键盘输入应用程序的。它有很多可以自动处理重复的键,可以把键码转换成ASCII字符等的功能,但是这些功能,游戏都不需要,而且,这会导致更宝贵的处理器循环的浪费。
5. Win32键盘处理代码虽然可以为你捕获一些键(比如Alt),但是这需要特殊的消息处理,才能够得到正确的操作。
6. 消息处理不是这个世界上最快的事情。应用程序得到了很多所需的鼠标消息,但是你必须等到这些消息队列空了以后才能够渲染桢,这将导致整个应用程序变慢。
DirectInput对象和设备
首先要定义程序要用的主DirectInput对象及设备的对象:
LPDIRECTINPUT8 dinput;
LPDIRECTINPUTDEVICE8 dinputdev;
初始化 DirectInput对象:
HRESULT result = DirectInput8Create(
GetModuleHandle(NULL),
DIRECTINPUT_VERSION,
IID_IDirectInput8,
(void**)&dinput,
NULL
);
初始化对象之后,可以使用这个对象创建新的DirectInput设备:
result = dinput->CreateDevice(GUID_SysKeyboard,&dikeyboard,NULL);
DirectInput8Create(
HINSTANCE hinst, //当前程序的实例句柄。如果这个当前实例不能直接取得,那么获得它的方便方法是用GetModuleHandle函数
DWORD dwVersion, //DirectInput版本 总为DIRECT_INPUT_VERSION即可。
REFIID riidltf, //想要使用的DirectInput版本的引用标识符。IID_IDirectInput8
LPVOID *ppvOut, //指向主DirectInput对象指针的指针
LPUNKNOWN punkOuter //总是NULL
);
HRESULT CreateDevice(
REFGUID rguid, //要创建的对象类型,GUID_SysKeyboard,GUID_SysMouse
LPDIRECTINPUTDEVICE *lplpDirectInputDevice,//接收DirectInput设备句柄的地址的设备指针
LPUNKNOWN pUnkOuter //总是NULL
);
初始化键盘和鼠标
一旦拥有了键盘和鼠标的DirectInput对象及设备对象,就可以初始化键盘和鼠标句柄。为输入做准备。- 设置数据格式
HRESULT SetDataFormat(
LPCDIDATAFORMAT lpdf //对于键盘,应传递c_dfDIKeyboard作为参数;对于鼠标,应传递c_dfDIMouse作为参数。
);
2. 设置协作级别
按优先级决定DirectInput将键盘或鼠标输入传递给程序的程度。
HRESULT SetCooperativeLevel(
HWND hwnd, //窗口句柄
DWORD dwFlags //指定程序对键盘和鼠标所拥有的优先级。键盘常用DISCL_NONEXCLUSIVE | DISCL_FOREGROUND.
);
3.获取设备
最后一步是用Acquire函数获取键盘或鼠标设备。
HRESULT Acquire(VOID);
//如果返回值为正( DI_OK ),则说明成功地获得了设备。对于键盘,此时可以开始检查键盘按键了;对于鼠标,此时可以开始检查鼠标移动和按键了。
//注意:在游戏结束之前必须反获取设备,否则DirectInput会处于不稳定状态。
HRESULT Unacquire(VOID);
读取键盘按键和鼠标
- 读取键盘按键
需要在游戏循环的某个地方轮询键盘以便更新键值。
首先我们需要定义一个存放键值的数组,以便接受键盘设备状态
char keys[256];//我们必须通过轮询键盘来填充这个字符数组,实现这个目标需要调用GetDeviceState函数。
HRESULT GetDeviceState(
DWORD cbData, // 用于填充数据的设备状态缓冲区的大小。
LPVOID lpvData //指向数据的指针。
);
//轮询及检查按键示例:
dikeyboard->GetDeviceState(sizeof(keys),(LPVOID)&keys);
if(keys[DIK_ESCAPE]&0x80)
{
//ESCAPE key was pressed,so do something!
}
读取鼠标
结构体:
typedef struct DIMOUSESTATE{
LONG lx;
LONG ly;
LONG lz;
BYTE rgbButtons[4];//保存鼠标按钮按下的结果。
}DIMOUSESTATE;
注意:lx ly 是鼠标移动,而不是绝对位置,所以如果想用鼠标定位值来绘制自己的鼠标指针则必须保留老的位置值。
如果想检查某个特定按钮,可以如下编写代码:
button_1 = obj.rgbButtons[0]&0x80;
使用define 是探测按钮状态的更为方便的方法:
#define BUTTON_DOWN(obj,button) (obj.rgbButtons[button]&0x80)
button_1 = BUTTON_DOWN(mouse_state,0);