#pragma once
#include <windows.h>
#include <basetsd.h>
#include <commctrl.h>
#include <dinput.h>
#include <dinputd.h>
#include <oleauto.h>
#include <shellapi.h>
#include <wbemidl.h>
#pragma warning( disable : 4996 ) // disable deprecated warning
#include <strsafe.h>
#pragma warning( disable : 4996 ) // disable deprecated warning
struct DI_ENUM_CONTEXT
{
DIJOYCONFIG* pPreferredJoyCfg;
bool bPreferredJoyCfgValid;
};
struct XINPUT_DEVICE_NODE
{
DWORD dwVidPid;
XINPUT_DEVICE_NODE* pNext;
};
class Joystick
{
public:
Joystick();
~Joystick();
public:
bool InitDirectInput();
void FreeDirectInput();
bool UpdateDirectInput(DIJOYSTATE2 &js);
private:
static BOOL CALLBACK EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* user);
static BOOL CALLBACK EnumJoysticksCallback(const DIDEVICEINSTANCE* pdidInstance, VOID* user);
private:
LPDIRECTINPUT8 g_pDI;
LPDIRECTINPUTDEVICE8 g_pJoystick;
DI_ENUM_CONTEXT g_EnumContext;
};
#include "stdafx.h"
#include "JoyStick.h"
#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
Joystick::Joystick()
{
g_pDI = NULL;
g_pJoystick = NULL;
}
Joystick::~Joystick()
{
FreeDirectInput()
}
BOOL Joystick::EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE * pdidoi, VOID * user)
{
Joystick* pJoy = (Joystick*)user;
// For axes that are returned, set the DIPROP_RANGE property for the
// enumerated axis in order to scale min/max values.
if (pdidoi->dwType & DIDFT_AXIS)
{
DIPROPRANGE diprg;
diprg.diph.dwSize = sizeof(DIPROPRANGE);
diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
diprg.diph.dwHow = DIPH_BYID;
diprg.diph.dwObj = pdidoi->dwType; // Specify the enumerated axis
diprg.lMin = -1000;
diprg.lMax = +1000;
// Set the range for the axis
if (FAILED(pJoy->g_pJoystick->SetProperty(DIPROP_RANGE, &diprg.diph)))
return DIENUM_STOP;
}
return DIENUM_CONTINUE;
}
//-----------------------------------------------------------------------------
// Name: EnumJoysticksCallback()
// Desc: Called once for each enumerated Joystick. If we find one, create a
// device interface on it so we can play with it.
//-----------------------------------------------------------------------------
BOOL CALLBACK Joystick::EnumJoysticksCallback(const DIDEVICEINSTANCE* pdidInstance,VOID* user)
{
Joystick* pJoy = (Joystick*)user;
//
HRESULT hr;
// Skip anything other than the perferred Joystick device as defined by the control panel.
// Instead you could store all the enumerated Joysticks and let the user pick.
if (pJoy->g_EnumContext.bPreferredJoyCfgValid &&
!IsEqualGUID(pdidInstance->guidInstance, pJoy->g_EnumContext.pPreferredJoyCfg->guidInstance))
return DIENUM_CONTINUE;
// Obtain an interface to the enumerated Joystick.
hr = pJoy->g_pDI->CreateDevice(pdidInstance->guidInstance, &pJoy->g_pJoystick, NULL);
// If it failed, then we can't use this Joystick. (Maybe the user unplugged
// it while we were in the middle of enumerating it.)
if (FAILED(hr))
return DIENUM_CONTINUE;
// Stop enumeration. Note: we're just taking the first Joystick we get. You
// could store all the enumerated Joysticks and let the user pick.
return DIENUM_STOP;
}
//-----------------------------------------------------------------------------
// Name: InitDirectInput()
// Desc: Initialize the DirectInput variables.
//-----------------------------------------------------------------------------
bool Joystick::InitDirectInput()
{
HRESULT hr= FALSE;
//1.创建Direct输出
if (FAILED(hr = DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION,IID_IDirectInput8, (VOID**)&g_pDI, NULL)))
return false;
//2.Joystick配置
DIJOYCONFIG PreferredJoyCfg = { 0 };
g_EnumContext.pPreferredJoyCfg = &PreferredJoyCfg;
g_EnumContext.bPreferredJoyCfgValid = false;
//2.1 创建配置
IDirectInputJoyConfig8* pJoyConfig = NULL;
if (FAILED(hr = g_pDI->QueryInterface(IID_IDirectInputJoyConfig8, (void**)&pJoyConfig)))
return false;
//2.2 获取配置参数
PreferredJoyCfg.dwSize = sizeof(PreferredJoyCfg);
// This function is expected to fail if no Joystick is attached
if (SUCCEEDED(pJoyConfig->GetConfig(0, &PreferredJoyCfg, DIJC_GUIDINSTANCE)))
g_EnumContext.bPreferredJoyCfgValid = true;
//2.3 释放
SAFE_RELEASE(pJoyConfig);
// 3.查找Joystick
if (FAILED(hr = g_pDI->EnumDevices(DI8DEVCLASS_GAMECTRL,EnumJoysticksCallback,this, DIEDFL_ATTACHEDONLY)))
return false;
// 4.判断是否有
if (NULL == g_pJoystick)
{
MessageBox(NULL, TEXT("Joystick not found. The sample will now exit."),
TEXT("Joystick"),
MB_ICONERROR | MB_OK);;
return false;
}
// Set the data format to "simple Joystick" - a predefined data format
// A data format specifies which controls on a device we are interested in,
// and how they should be reported. This tells DInput that we will be
// passing a DIJOYSTATE2 structure to IDirectInputDevice::GetDeviceState().
if (FAILED(hr = g_pJoystick->SetDataFormat(&c_dfDIJoystick2)))
return false;
//
// Set the cooperative level to let DInput know how this device should
// interact with the system and with other DInput applications.
/*if (FAILED(hr = g_pJoystick->SetCooperativeLevel(NULL, DISCL_EXCLUSIVE |
DISCL_FOREGROUND)))
return false;*/
// Enumerate the Joystick objects. The callback function enabled user
// interface elements for objects that are found, and sets the min/max
// values property for discovered axes.
if (FAILED(hr = g_pJoystick->EnumObjects(EnumObjectsCallback,this, DIDFT_ALL)))
return false;
return true;
}
void Joystick::FreeDirectInput()
{
// Unacquire the device one last time just in case
// the app tried to exit while the device is still acquired.
if (g_pJoystick)
g_pJoystick->Unacquire();
// Release any DirectInput objects.
SAFE_RELEASE(g_pJoystick);
SAFE_RELEASE(g_pDI);
}
bool Joystick::UpdateDirectInput(DIJOYSTATE2 & js)
{
HRESULT hr;
if (NULL == g_pJoystick)
return false;
// Make sure the device is acquired, if we are gaining focus.
hr = g_pJoystick->Acquire();
// Poll the device to read the current state
hr |= g_pJoystick->Poll();
if (FAILED(hr))
{
// DInput is telling us that the input stream has been
// interrupted. We aren't tracking any state between polls, so
// we don't have any special reset that needs to be done. We
// just re-acquire and try again.
hr = g_pJoystick->Acquire();
while (hr == DIERR_INPUTLOST)
hr = g_pJoystick->Acquire();
// hr may be DIERR_OTHERAPPHASPRIO or other errors. This
// may occur when the app is minimized or in the process of
// switching, so just try again later
return false;
}
// Get the input's device state
if (FAILED(hr = g_pJoystick->GetDeviceState(sizeof(DIJOYSTATE2), &js)))
return false; // The device should have been acquired during the Poll()
return true;
}