- A+
游戏中可以使用的输入方法太多了
先来看看使用的差别
那么使用DirectInput比使用标准的API调用有什么优势呢?
1. Win32 API不是为游戏或者速度而设计的
2. Win32最多只能支持那种简单的摇杆,如果是复杂的摇杆,比如那种带几个轴的,8到10个按钮的等等,Win32就支持不了了。
3. 对鼠标的支持被限制在3个按钮,2个轴,一个滚轮。但是今天的市场上,很多鼠标有4个,5个按钮,甚至更多。
4. Win32对键盘的支持,主要是被设计用来支持键盘输入应用程序的。它有很多可以自动处理重复的键,可以把键码转换成ASCII字符等的功能,但是这些功能,游戏都不需要,而且,这会导致更宝贵的处理器循环的浪费。
5. Win32键盘处理代码虽然可以为你捕获一些键(比如Alt),但是这需要特殊的消息处理,才能够得到正确的操作。
6. 消息处理不是这个世界上最快的事情。应用程序得到了很多所需的鼠标消息,但是你必须等到这些消息队列空了以后才能够渲染桢,这将导致整个应用程序变慢。
使用DirectInput需要进行初始化
就像初始化Direct3D那样
引入头文件
链接库文件
1 2 3 |
#include <dinput.h> #pragma comment(lib,"dinput8") #pragma comment(lib,"dxguid") |
不包含dxguid.lib,使用一些内置变量就会报错
上网搜了下,说是必须包含的
然后就是全局变量了
1 2 3 |
LPDIRECTINPUT8 dinput = NULL; LPDIRECTINPUTDEVICE8 dikeyboard = NULL; LPDIRECTINPUTDEVICE8 dimouse = NULL; |
类似于初始化Direct3D就不解释了
开始初始化(鼠标和键盘的是一样的)
只是指定的标识不一样
1.初始化DirectInput对象
2.初始化DirectInput设备对象
3.设置数据格式
4.设置协作级别
5.获取设备
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&dinput,NULL); if (dinput == NULL) { MessageBox(NULL, L"初始化dinput失败", L"失败", MB_OK); return false; } dinput->CreateDevice(GUID_SysKeyboard, &dikeyboard, NULL); if (dikeyboard == NULL) { MessageBox(NULL, L"初始化键盘设备失败", L"失败", MB_OK); return false; } dikeyboard->SetDataFormat(&c_dfDIKeyboard); dikeyboard->SetCooperativeLevel(hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND); if (dikeyboard->Acquire() != DI_OK) { MessageBox(NULL, L"获取设备失败", L"错误", MB_OK); return false; } dinput->CreateDevice(GUID_SysMouse, &dimouse, NULL); if (dimouse == NULL) { MessageBox(NULL, L"初始化dimouse失败", L"错误", MB_OK); return false; } dimouse->SetDataFormat(&c_dfDIMouse); dimouse->SetCooperativeLevel(hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND); if (dimouse->Acquire() != DI_OK) { MessageBox(NULL, L"获取鼠标设备失败", L"错误", MB_OK); return false; } |
123456789101112 HRESULT DirectInput8Create(HINSTANCE hinst,DWORD dwVersion,REFIID riidltf,LPVOID * ppvOut,LPUNKNOWN punkOuter)* hinst是当前程序的实例句柄,使用GetModuleHandle(NULL)获取。* dwVersion一般固定为DIRECTINPUT_VERSION。* riidltf是要使用的DieectInput的引用标识符,IID_IDirectInput8A或IID_IDirectInput8W或IID_IDirectInput8 。* ppvOut指向DirectInput对象的指针,这里是双重指针。* punkOuter Pointer to the address of the controlling object's IUnknown interface for COM aggregation, or NULL if the interface is not aggregated. Most calling applications pass NULL. If aggregation is requested, the object returned in ppvOut is a pointer to<strong>IUnknown</strong>, as required by COM aggregation.(设为NULL就好- -)
123456789 HRESULT CreateDevice(REFGUID rguid,LPDIRECTINPUTDEVICE * lplpDirectInputDevice,LPUNKNOWN pUnkOuter )* rguid 要创建的对象类型GUID_SysKeyboard 系统默认键盘GUID_SysMouse 系统默认鼠标* lplpDirectInputDevice 接受DirectInput设备的地址的设备指针* pUnkOuter 为NULL。
123456789 HRESULT SetDataFormat(LPCDIDATAFORMAT lpdf)*lpdf 设备类型,可以为c_dfDIKeyboardc_dfDIMousec_dfDIMouse2c_dfDIJoystickc_dfDIJoystick2
12345678910111213141516 HRESULT SetCooperativeLevel(HWND hwnd,DWORD dwFlags)*hwnd 窗口句柄*dwFlags 指定程序对键盘或鼠标的优先级(一般使用DISCL_NONEXCLUSIVE|DISCL_FOREGROUND)DISCL_BACKGROUNDThe application requires background access. If background access is granted, the device can be acquired at any time, even when the associated window is not the active window.DISCL_EXCLUSIVEThe application requires exclusive access. If exclusive access is granted, no other instance of the device can obtain exclusive access to the device while it is acquired. However, nonexclusive access to the device is always permitted, even if another application has obtained exclusive access. An application that acquires the mouse or keyboard device in exclusive mode should always unacquire the devices when it receives WM_ENTERSIZEMOVE and WM_ENTERMENULOOP messages. Otherwise, the user cannot manipulate the menu or move and resize the window.DISCL_FOREGROUNDThe application requires foreground access. If foreground access is granted, the device is automatically unacquired when the associated window moves to the background.DISCL_NONEXCLUSIVEThe application requires nonexclusive access. Access to the device does not int-erfere with other applications that are accessing the same device.DISCL_NOWINKEYDisable the Windows logo key. Setting this flag ensures that the user cannot inadvertently break out of the application. Note, however, that DISCL_NOWINKEY has no effect when the default action mapping user interface (UI) is displayed, and the Windows logo key will operate normally as long as that UI is present.
最后的Acquire就是获取设备的使用权限了
当其他进程占用后,又要重新获取Acquire
不然就会出现问题
同样要记得结束的时候Unacquire和释放内存
1 2 3 4 5 6 7 8 9 10 11 |
if (dikeyboard) { dikeyboard->Unacquire(); dikeyboard->Release(); dikeyboard = NULL; } if (dimouse) { dimouse->Unacquire(); dimouse->Release(); dimouse = NULL; } |
下面在游戏循环中读取按键和鼠标信息
先定义保存信息的变量
1 2 |
char keys[256]; DIMOUSESTATE state; |
然后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//键盘按键判断 dimouse->Acquire(); dikeyboard->Acquire(); dikeyboard->GetDeviceState(sizeof(keys), (LPVOID)&keys); if (keys[DIK_0] & 0x80) { MessageBox(NULL, L"按键0", L"成功", MB_OK); } //鼠标按键判断 dimouse->GetDeviceState(sizeof(state), (LPVOID)&state); if (state.rgbButtons[0] & 0x80) { MessageBox(NULL, L"鼠标左键按下", L"成功", MB_OK); } if (state.rgbButtons[1] & 0x80) { MessageBox(NULL, L"鼠标右键按下",L"成功", MB_OK); } |
可以看到我在循环中Acquire
因为我不这样做,它就发神经
这里就不详细说了,看字面意思
运行,都成功了!