⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rdxjoystick.h

📁 F:RobinGameincludeinputRDXJoystick.rar DX8 游戏手柄完整类
💻 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 + -