📄 rdxjoystick.h
字号:
// RDXJoystick.h
// 作者:陈峰
// 使用方法:
// 在 init 中运行 initJoystick(...)
// 在 loop 中运行 captureJoystick() 和 set... get...
#ifndef _RDXJoystick
#define _RDXJoystick
#include "../../include/func/RFunc.h"
#define SafeDelete ( pObject ){ if( pObject!=NULL ){ delete pObject; pObject = NULL } }
#define SafeRelease( pObject ){ if( pObject!=NULL ){ pObject->Release(); pObject = NULL; } }
//◎◎◎◎ class : RDXJoystick ◎◎◎◎//
class RDXJoystick
{
private:
static RDXJoystick* pRDXJoystick;
HWND hwnd;
HRESULT hr;
LPDIRECTINPUT8 lpDirectInput;
LPDIRECTINPUTDEVICE8 lpDirectInputDevice;
LPDIRECTINPUTEFFECT lpDirectEffect;
DIPROPRANGE dipROPRANGE;
DIPROPDWORD dipROPDWORD;
DIJOYSTATE2 diJOYSTATE2;
DWORD dwNumForceFeedbackAxis; // 力回馈轴的个数
DIEFFECT diEffect; // 力回馈属性数据
int rangeMin;
int rangeMax;
int rangeDeadZone;
public:
// 构造 和 析构
RDXJoystick()
{
pRDXJoystick = this;
lpDirectInput = NULL;
lpDirectInputDevice = NULL;
lpDirectEffect = NULL;
dwNumForceFeedbackAxis = 0;
}
~RDXJoystick()
{
if( lpDirectInputDevice!=NULL )
lpDirectInputDevice->Unacquire();
SafeRelease( lpDirectEffect );
SafeRelease( lpDirectInputDevice );
SafeRelease( lpDirectInput );
}
protected:
// 用于回调自身的函数
static RDXJoystick* getRDXJoystick()
{
return pRDXJoystick;
}
inline LPDIRECTINPUT8 getDirectInput()
{
return lpDirectInput;
}
// 枚举回调函数 友元声明
friend BOOL CALLBACK EnumJoysticksCallback( const DIDEVICEINSTANCE* pdidInstance, VOID* lpVoid );
friend BOOL CALLBACK EnumAxesCallback( const DIDEVICEOBJECTINSTANCE* pdidoi, VOID* pContext );
public:
// 初始化游戏手柄
bool initJoystick( HINSTANCE hinstance, HWND inhwnd, bool& joystickSucceed, bool& forceFeedbackSucceed,
int min=-1000, int max=1000, int deadZone=1 )
{
hwnd = inhwnd;
rangeMin = min;
rangeMax = max;
rangeDeadZone = deadZone;
joystickSucceed = 0;
forceFeedbackSucceed = 0;
//◎◎ 建立 IDirectInput8 接口对象 ◎◎//
hr = DirectInput8Create( hinstance, DIRECTINPUT_VERSION,
IID_IDirectInput8, (VOID**)&lpDirectInput, NULL );
if( FAILED(hr) )
{
MessageBox( hwnd, "Create <lpDirectInput> failed !!!", "warning", MB_OK|MB_ICONINFORMATION );
return false;
}
//◎◎ 游戏手柄初始化 ◎◎//
// 枚举所有已经安装的游戏手柄 回调EnumJoysticksCallback(...)函数
hr = lpDirectInput->EnumDevices( DI8DEVCLASS_GAMECTRL,
EnumJoysticksCallback,
&lpDirectInputDevice,
DIEDFL_ATTACHEDONLY | DIEDFL_FORCEFEEDBACK ); // 带力回馈
if( lpDirectInputDevice==NULL )
{
cout<<"warning : initJoystick() : Your joystick is not forceFeedback device !!!"<<endl;
// 枚举不带力回馈的手柄
hr = lpDirectInput->EnumDevices( DI8DEVCLASS_GAMECTRL,
EnumJoysticksCallback,
&lpDirectInputDevice,
DIEDFL_ATTACHEDONLY ); // 不带力回馈
if( FAILED(hr) )
{
MessageBox( hwnd, "Enum joystick device failed !!!", "warning", MB_OK|MB_ICONINFORMATION );
return false;
}
}
// 检查枚举结果
if( lpDirectInputDevice==NULL )
{
MessageBox( hwnd, "No joystick, please check your joystick connection state !!!", "warning",
MB_OK|MB_ICONINFORMATION );
return false;
}
// 设置游戏手柄设备的数据格式
hr = lpDirectInputDevice->SetDataFormat( &c_dfDIJoystick2 ); // c_dfDIJoystick2 是 DX 预先定制的
// 表示 DIJOYSTATE2 结构数据
if( FAILED(hr) )
{
MessageBox( hwnd, "Set joystick read data failed !!!", "warning",
MB_OK|MB_ICONINFORMATION );
SafeRelease( lpDirectInputDevice );
SafeRelease( lpDirectInput );
return false;
}
// 设置游戏手柄的协调级别
hr = lpDirectInputDevice->SetCooperativeLevel( hwnd, DISCL_EXCLUSIVE | DISCL_FOREGROUND );
if( FAILED(hr) )
{
MessageBox( hwnd, "Set cooperative level failed !!!", "warning",
MB_OK|MB_ICONINFORMATION );
SafeRelease( lpDirectInputDevice );
SafeRelease( lpDirectInput );
return false;
}
// 设置游戏手柄的轴范围属性
dipROPRANGE.diph.dwSize = sizeof( DIPROPRANGE );
dipROPRANGE.diph.dwHeaderSize = sizeof( DIPROPHEADER );
dipROPRANGE.diph.dwObj = 0;
dipROPRANGE.diph.dwHow = DIPH_DEVICE;
dipROPRANGE.lMin = min;
dipROPRANGE.lMax = max;
hr = lpDirectInputDevice->SetProperty( DIPROP_RANGE, &dipROPRANGE.diph );
if( FAILED(hr) )
{
MessageBox( hwnd, "Set range of axis failed !!!", "warning",
MB_OK|MB_ICONINFORMATION );
SafeRelease( lpDirectInputDevice );
SafeRelease( lpDirectInput );
return false;
}
// 设置游戏手柄的盲区 最大值 10000
dipROPDWORD.diph.dwSize = sizeof( DIPROPDWORD );
dipROPDWORD.diph.dwHeaderSize = sizeof( DIPROPHEADER );
dipROPDWORD.diph.dwObj = 0;
dipROPDWORD.diph.dwHow = DIPH_DEVICE;
dipROPDWORD.dwData = 100 * deadZone;
hr = lpDirectInputDevice->SetProperty( DIPROP_DEADZONE, &dipROPDWORD.diph );
if( FAILED(hr) )
{
MessageBox( hwnd, "Set dead zone of axis failed !!!", "warning",
MB_OK|MB_ICONINFORMATION );
SafeRelease( lpDirectInputDevice );
SafeRelease( lpDirectInput );
return false;
}
// 初始化DIJOYSTATE2数据 准备捕捉手柄数据
ZeroMemory( &diJOYSTATE2, sizeof(DIJOYSTATE2) );
// 最后游戏手柄初始化成功
joystickSucceed = 1;
//◎◎ 力回馈初始化 ◎◎//
// 可以没有力回馈设备 但要保证游戏手柄基本功能使用 所以不要返回0 只需提示就好了
int FFBinitStep = 0; // 成功初始化步骤计数
// 自动中心位置
DIPROPDWORD diPropAutoCenter;
diPropAutoCenter.diph.dwSize = sizeof(DIPROPDWORD);
diPropAutoCenter.diph.dwHeaderSize = sizeof(DIPROPHEADER);
diPropAutoCenter.diph.dwObj = 0;
diPropAutoCenter.diph.dwHow = DIPH_DEVICE;
diPropAutoCenter.dwData = FALSE;
hr = lpDirectInputDevice->SetProperty( DIPROP_AUTOCENTER, &diPropAutoCenter.diph );
if( FAILED(hr) )
cout<<"warning : initJoystick() : Set auto center failed !!!"<<endl;
else
FFBinitStep++; // 成功的话 FFBinitStep == 1
// 枚举力回馈震动轴
hr = lpDirectInputDevice->EnumObjects( EnumAxesCallback,
(VOID*)&dwNumForceFeedbackAxis,
DIDFT_AXIS );
if( FAILED(hr) )
cout<<"warning : initJoystick() : Enum effects axis failed !!!"<<endl;
else
FFBinitStep++; // 成功的话 FFBinitStep == 2
if( dwNumForceFeedbackAxis > 2 ) // 如果多于两个轴就限定成两个轴
dwNumForceFeedbackAxis = 2;
// 创建力回馈效果
DWORD rgdwAxes[2] = { DIJOFS_X, DIJOFS_Y };
LONG rglDirection[2] = { 0, 0 };
DICONSTANTFORCE cf = { 0 };
DIEFFECT eff;
ZeroMemory( &eff, sizeof(eff) );
eff.dwSize = sizeof(DIEFFECT);
eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
eff.dwDuration = INFINITE;
eff.dwSamplePeriod = 0;
eff.dwGain = DI_FFNOMINALMAX;
eff.dwTriggerButton = DIEB_NOTRIGGER;
eff.dwTriggerRepeatInterval = 0;
eff.cAxes = dwNumForceFeedbackAxis;
eff.rgdwAxes = rgdwAxes;
eff.rglDirection = rglDirection;
eff.lpEnvelope = 0;
eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
eff.lpvTypeSpecificParams = &cf;
eff.dwStartDelay = 0;
hr = lpDirectInputDevice->CreateEffect( GUID_ConstantForce,
&eff,
&lpDirectEffect,
NULL );
if( FAILED(hr) )
cout<<"warning : initJoystick() : Create effect failed !!!"<<endl;
else
FFBinitStep++; // 成功的话 FFBinitStep == 3
if( lpDirectEffect == NULL )
cout<<"warning : initJoystick() : You can not use <lpDirectEffect> failed !!!"<<endl;
else
FFBinitStep++; // 成功的话 FFBinitStep == 4
if( FFBinitStep == 4 ) // 四步都成功了
forceFeedbackSucceed = 1;
// 全部成功
return true;
}
// 捕捉输入
bool captureJoystick()
{
if( lpDirectInputDevice==NULL )
return false;
// 获取访问权
hr = lpDirectInputDevice->Acquire();
if( FAILED(hr) )
{
MessageBox( hwnd, "captureJoystick() : Acquire failed !!!", "warning",
MB_OK|MB_ICONINFORMATION );
lpDirectInputDevice->Unacquire();
SafeRelease( lpDirectInputDevice );
SafeRelease( lpDirectInput );
return false;
}
// 检测游戏手柄的 poll
hr = lpDirectInputDevice->Poll();
if( FAILED(hr) )
{
MessageBox( hwnd, "captureJoystick() : Check poll failed !!!", "warning",
MB_OK|MB_ICONINFORMATION );
SafeRelease( lpDirectInputDevice );
SafeRelease( lpDirectInput );
return false;
}
// 获取输入
hr = lpDirectInputDevice->GetDeviceState( sizeof(DIJOYSTATE2), &diJOYSTATE2 );
if( FAILED(hr) )
{
MessageBox( hwnd, "captureJoystick() : Get devie state failed !!!", "warning",
MB_OK|MB_ICONINFORMATION );
SafeRelease( lpDirectInputDevice );
SafeRelease( lpDirectInput );
return false;
}
// 全部成功
return true;
}
// 获取
void Acquire()
{
if( lpDirectInputDevice!=NULL )
lpDirectInputDevice->Acquire();
}
// 释放
void Unacquire()
{
if( lpDirectInputDevice!=NULL )
lpDirectInputDevice->Unacquire();
}
// 输出范围值
int getRangeMax()
{
return rangeMax;
}
int getRangeMin()
{
return rangeMin;
}
int getRangeDeadZone()
{
return rangeDeadZone;
}
//◎◎◎◎ 得到所有输出 ◎◎◎◎//
// 输出 ax, ay, az, rz 数据
float getValueOfAxisX()
{
return float(diJOYSTATE2.lX) / float(rangeMax);
}
float getValueOfAxisY()
{
return float(diJOYSTATE2.lY) / float(rangeMax);
}
float getValueOfAxisZ()
{
return float(diJOYSTATE2.lZ) / float(rangeMax);
}
float getValueOfAxisRZ()
{
return float(diJOYSTATE2.lRz) / float(rangeMax);
}
// 输出 POV (Point of view) 相当于 0, 45, 90, 135, 180, 225, 270,315 八个角度
// 不按 -1
// 上 0 右上 4500
// 右 9000 右下 13500
// 下 18000 左下 22500
// 左 27000 左上 31500
long getValueOfPOV()
{
return diJOYSTATE2.rgdwPOV[0];
}
// 输出按键情况(已经做了 -1 的偏移处理)
bool getButtonPressed( int buttonID )
{
if( diJOYSTATE2.rgbButtons[buttonID-1] & 0x80 )
return true;
else
return false;
}
//◎◎◎◎ 力回馈效果 ◎◎◎◎//
// 改变相对于中心位置力属性
void changeForce( int x, int y, bool isUse )
{
if( lpDirectEffect != NULL && isUse )
{
DICONSTANTFORCE cf;
LONG lDirection[2];
if( dwNumForceFeedbackAxis == 1 )
{
cf.lMagnitude = long(x);
lDirection[0] = 0;
}
else
{
lDirection[0] = long(x);
lDirection[1] = long(y);
cf.lMagnitude = long( sqrt(float(x)*float(x)+float(y)*float(y)) );
}
DIEFFECT eff;
ZeroMemory( &eff, sizeof(eff) );
eff.dwSize = sizeof(DIEFFECT);
eff.dwFlags = DIEFF_CARTESIAN | DIEFF_OBJECTOFFSETS;
eff.cAxes = dwNumForceFeedbackAxis;
eff.rglDirection = lDirection;
eff.lpEnvelope = 0;
eff.cbTypeSpecificParams = sizeof(DICONSTANTFORCE);
eff.lpvTypeSpecificParams = &cf;
eff.dwStartDelay = 0;
hr = lpDirectEffect->SetParameters( &eff, DIEP_DIRECTION |
DIEP_TYPESPECIFICPARAMS |
DIEP_START );
if( FAILED(hr) )
{
MessageBox( hwnd, "changeForce() : Set parameters failed !!!", "warning",
MB_OK|MB_ICONINFORMATION );
}
}
}
// 播放
void playEffect()
{
if( lpDirectEffect != NULL )
lpDirectEffect->Start(1, 0);
}
// 停止
void stopEffect()
{
if( lpDirectEffect != NULL )
lpDirectEffect->Stop();
}
// 输出震动轴个数
int getForceAxesNum()
{
return int(dwNumForceFeedbackAxis);
}
};
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -