目的:简化开发学习过程,以最小代码清晰展示某功能的实现。
手柄设备和键盘鼠标是不同的,因为手柄不是必须的输入设备,因此系统没有事先定义好GUID供用户调用,并且手柄设备差异很大,因此只能用轮询来获得手柄设备的ID.
本文为新手解释了如何初始化DirectInput设备为手柄,高手请忽略。
整体思路是这样的,首先创建DirectInput对象,之后用这个对象来轮询设备,从而获得可用的设备ID,之后通过这个ID来创建设备:
#include "stdafx.h"
#include <dinput.h>
#include <iostream>
using namespace std;
#pragma comment(lib, "dinput8.lib")
#pragma comment(lib, "DXGuid.lib")//unresolved external symbol for guid
#define JOYSTICK_BUTTON_STATE(x) ((joy_state.rgbButtons[x] &0x80) ? TRUE : FALSE)
#define MY_BUFSIZE 1024
//This is the callback function that takes the 2nd arguement pretty useful for handling DI in a class
BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE* pdidInstance, VOID* pContext)
{ //Name of general usb pad device " USB Joystick ", but don't forget the white spaces
if (0 == wcscmp(pdidInstance->tszProductName, L" USB Joystick "))//You can also create the device within the callback and pass the device address
{ //Thus, you don't have to enum the device by the name
GUID* t;
t = (GUID*)pContext;//Retrieving the GUID thru the 2nd param
*t = pdidInstance->guidInstance;//Now t takes over the pGuid, so the address of GUID in calling func is t. //if(SUCCEEDED(pContext -> CreateDevice(pdidInstance->guidInstance, &lpJoystick, NULL)))...and then pass the lpJoystick thru pContext again
return DIENUM_STOP;
}
return DIENUM_CONTINUE;
}
LRESULT InitDI(LPDIRECTINPUT8* lpdi, LPDIRECTINPUTDEVICE8* lpdev)
{
GUID id;
auto result = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)lpdi, NULL);
(*lpdi)->EnumDevices(DI8DEVCLASS_GAMECTRL, EnumJoysticksCallback, &id, DIEDFL_ATTACHEDONLY);//id can be retrieved by the 3rd param
(*lpdi)->CreateDevice(id, lpdev, NULL);//The * mark is very tricky that it gets the content of the pointer.
(*lpdev)->SetDataFormat(&c_dfDIJoystick);//All the secret is here if it is necessary to avoid globals or statics.
HWND hwndFound;
wchar_t pszOldWindowTitle[MY_BUFSIZE];
GetConsoleTitle(pszOldWindowTitle, MY_BUFSIZE);
hwndFound = FindWindow(NULL, pszOldWindowTitle);//locate hwnd in a console app
(*lpdev)->SetCooperativeLevel(hwndFound, DISCL_BACKGROUND | DISCL_EXCLUSIVE);
if (FAILED((*lpdev)->Acquire()))
{
MessageBox(hwndFound, L"Cannot acquire joystic!", L"Error", MB_ICONERROR);
return E_FAIL;
}
return S_OK;
}
int main()
{
LPDIRECTINPUT8 lpDI = nullptr;
LPDIRECTINPUTDEVICE8 lpjsDev = nullptr;
InitDI(&lpDI, &lpjsDev);
DIJOYSTATE joy_state;
bool f = true;
lpjsDev->Poll();
while (f)
{
lpjsDev->GetDeviceState(sizeof(DIJOYSTATE), &joy_state);
if (JOYSTICK_BUTTON_STATE(0))
{
cout << "This is to test if the joystick device is etablished." << endl;
}
if (JOYSTICK_BUTTON_STATE(8))
f = false;
}
lpjsDev->Unacquire();
lpjsDev->Release();
lpDI->Release();
return 0;
}
由于与回调函数内通讯比较困难,微软特意留了一个
pContext可以从
EnumDevices的第三个参数取回东西,因此在封装到类时,可以通过这个参数传递GUID或者DirectInput对象,避免使用全局变量或者初始化静态变量(回调函数需要在类中声明为静态,内部不能使用类成员)。