功能全面地封装了XInput的输入,
1. 普通按钮按下, 按住, 弹起状态检查,
2. 摇杆4个方向的按下, 按住, 弹起检查
3. 按键状态变化检测并且记录按下触发时间, 按住保持时间, 方便用来完全自定义的输入功能
4. 多手柄输入合并
CXinputHelper.h
#pragma once
#include <windows.h>
#include <xinput.h>
#include <tchar.h>
#include <thread>
#include <functional>
#include <string>
#include <map>
#pragma comment(lib, "xinput.lib")
#define PI (3.141592653589793f)
#define ANGLE_RANGE (22.5f)
#define XINPUT_GAMEPAD_GUIDE (0x00000400)
#define XINPUT_GAMEPAD_SHARE (0x00000800)
#define XINPUT_GAMEPAD_LEFT_TRIGGER (0x00010000)
#define XINPUT_GAMEPAD_RIGHT_TRIGGER (0x00020000)
#define XINPUT_GAMEPAD_LEFT_STICK (0x00040000)
#define XINPUT_GAMEPAD_RIGHT_STICK (0x00080000)
#ifdef _UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endif
// 手柄按键状态位
typedef union _GAME_PAD_BUTTON_MASK
{
DWORD dwButtons; // 标准按钮键值
// 按钮比特位
struct _Flags
{
DWORD DpadUp : 1; // 十字键 上
DWORD DpadDown : 1; // 十字键 下
DWORD DpadLeft : 1; // 十字键 左
DWORD DpadRight : 1; // 十字键 右
DWORD Start : 1; // 菜单键(开始键)
DWORD Back : 1; // 返回键(选择键)
DWORD LeftThumb : 1; // 左摇杆键
DWORD RightThumb : 1; // 右摇杆键
DWORD LeftShoulder : 1; // 左肩键
DWORD RightShoulder : 1; // 右肩键
DWORD Guide : 1; // 西瓜键(导航键)
DWORD Share : 1; // 分享键(假设, 未验证)
DWORD A : 1; // A
DWORD B : 1; // B
DWORD X : 1; // X
DWORD Y : 1; // Y
// 根据摇杆方向假设的摇杆方向键
DWORD LeftStickUp : 1; // 左摇杆 上
DWORD LeftStickDown : 1; // 左摇杆 下
DWORD LeftStickLeft : 1; // 左摇杆 左
DWORD LeftStickRight : 1; // 左摇杆 右
DWORD RightStickUp : 1; // 右摇杆 上
DWORD RightStickDown : 1; // 右摇杆 下
DWORD RightStickLeft : 1; // 右摇杆 左
DWORD RightStickRight : 1; // 右摇杆 右
DWORD LeftTrigger : 1; // 左扳机
DWORD RightTrigger : 1; // 右扳机
}Mask;
}GAME_PAD_BUTTON_MASK;
// 摇杆方向状态位
typedef union _GAME_PAD_BUTTON_STATE
{
uint8_t State; // 状态
// 按钮比特位
struct _Flags
{
uint8_t Down : 1; // 按下
uint8_t Hold : 1; // 按住
uint8_t Up : 1; // 弹起
}Mask;
}GAME_PAD_BUTTON_STATE;
typedef union _GAME_PAD_STICK_DIRECTION_STATE
{
uint32_t State; // 状态
// 按钮比特位
struct _Flags
{
uint32_t Up : 1; // 摇杆 上
uint32_t Down : 1; // 摇杆 下
uint32_t Left : 1; // 摇杆 左
uint32_t Right : 1; // 摇杆 右
}Mask;
}GAME_PAD_STICK_DIRECTION_STATE;
// 手柄按键状态位
typedef struct _GAME_PAD_BUTTON_INFO
{
uint8_t Value; // 按键值
GAME_PAD_BUTTON_STATE Flag; // 按键标志
DWORD dwTime; // 触发时间
DWORD dwDuration; // 持续时长
}GAME_PAD_BUTTON_INFO;
// 摇杆方向
typedef struct _GAME_PAD_STICK_DIRECTION
{
GAME_PAD_STICK_DIRECTION_STATE Direction; // 当前方向标志
GAME_PAD_BUTTON_INFO Up;
GAME_PAD_BUTTON_INFO Down;
GAME_PAD_BUTTON_INFO Left;
GAME_PAD_BUTTON_INFO Right;
}GAME_PAD_STICK_DIRECTION;
// 输入事件状态
typedef struct _INPUT_EVENT_STATE
{
DWORD dwIndex; // 手柄索引
DWORD dwButtonMask; // 按钮标识位掩码
XINPUT_STATE xinputState; // 手柄输入
DWORD dwTime; // 触发时间
DWORD dwDuration; // 触发时长
GAME_PAD_BUTTON_STATE curButtonFlag; // 触发状态(按下, 按住, 弹起)
GAME_PAD_STICK_DIRECTION curLeftStickDirection; // 左摇杆方向触发状态
GAME_PAD_STICK_DIRECTION curRightStickDirection; // 右摇杆方向触发状态
GAME_PAD_STICK_DIRECTION lastLeftStickDirection; // 上次左摇杆方向触发状态
GAME_PAD_STICK_DIRECTION lastRightStickDirection; // 上次右摇杆方向触发状态
GAME_PAD_STICK_DIRECTION stickDirection; // 摇杆方向触发状态
GAME_PAD_BUTTON_MASK buttonBitMask; // 按键位状态
DWORD dwButtons; // 触发按键
SHORT sThumbX; // 当前摇杆X值
SHORT sThumbY; // 当前摇杆Y值
BYTE bTrigger; // 扳机数据
BYTE fRight;
_INPUT_EVENT_STATE()
{
memset(this, 0, sizeof(*this));
}
}INPUT_EVENT_STATE;
// 输入事件变化回调
class CXInputHelper;
typedef bool (CXInputHelper::*pInputEventFn)(const INPUT_EVENT_STATE& state);
typedef struct _INPUT_EVENT_INFO
{
pInputEventFn eventCb; // 输入事件变化回调函数
INPUT_EVENT_STATE eventState; // 输入事件变化状态
_INPUT_EVENT_INFO(pInputEventFn cb)
:
eventCb(cb)
{
}
}INPUT_EVENT_INFO;
class CXInputHelper
{
public:
CXInputHelper();
virtual ~CXInputHelper();
bool Initialize();
void Uninitialize();
// 打印状态信息
virtual void PrintState(const INPUT_EVENT_STATE& state);
// 打印
void PrintText(LPCTSTR pFormat, ...);
void IgnoreLeftThumbEmpty(
bool bEnable = true // 允许空数据触发回调
);
void IgnoreRightThumbEmpty(
bool bEnable = true // 允许空数据触发回调
);
void SetInterval(
int millisecond = 10 // 数据采集间隔时间(毫秒)
);
void SetThumbThreshold(
int nLeftThumbThreshold = 4096, // 左摇杆触发阈值(死区)
int nRightThumbThreshold = 4096 // 右摇杆触发阈值(死区)
);
// 设置检测每个控制器输入数据回调
void SetRawStateCallback(
std::function<void(
DWORD dwIndex, // 控制器索引(有效值: 0 - 3)
const XINPUT_GAMEPAD& xGamepad // 控制器数据
)> cb
);
// 设置合并多个控制器输入数据回调
void SetMergeStateCallback(
std::function<void(
const XINPUT_GAMEPAD& xGamepad // 控制器数据
)> cb
);
// 设置检测每个控制器输入状态变化回调(发生按钮按下, 释放, 按住时触发)
void SetRawChangeCallback(
std::function<void(
const INPUT_EVENT_STATE& state // 回调信息
)> cb
);
// 设置合并多个控制器输入状态变化回调(发生按钮按下, 释放, 按住时触发)
void SetMergeChangeCallback(
std::function<void(
const INPUT_EVENT_STATE& state // 回调信息
)> cb
);
// 输入变化
virtual bool OnChangeDpadUp(const INPUT_EVENT_STATE& state);
virtual bool OnChangeDpadDown(const INPUT_EVENT_STATE& state);
virtual bool OnChangeDpadLeft(const INPUT_EVENT_STATE& state);
virtual bool OnChangeDpadRight(const INPUT_EVENT_STATE& state);
virtual bool OnChangeBack(const INPUT_EVENT_STATE& state);
virtual bool OnChangeStart(const INPUT_EVENT_STATE& state);
virtual bool OnChangeGuide(const INPUT_EVENT_STATE& state);
virtual bool OnChangeShare(const INPUT_EVENT_STATE& state);
virtual bool OnChangeA(const INPUT_EVENT_STATE& state);
virtual bool OnChangeB(const INPUT_EVENT_STATE& state);
virtual bool OnChangeX(const INPUT_EVENT_STATE& state);
virtual bool OnChangeY(const INPUT_EVENT_STATE& state);
virtual bool OnChangeLeftShoulder(const INPUT_EVENT_STATE& state);
virtual bool OnChangeRightShoulder(const INPUT_EVENT_STATE& state);
virtual bool OnChangeLeftTrigger(const INPUT_EVENT_STATE& state);
virtual bool OnChangeRightTrigger(const INPUT_EVENT_STATE& state);
virtual bool OnChangeLeftStick(const INPUT_EVENT_STATE& state);
virtual bool OnChangeRightStick(const INPUT_EVENT_STATE& state);
virtual bool OnChangeLeftThumb(const INPUT_EVENT_STATE& state);
virtual bool OnChangeRightThumb(const INPUT_EVENT_STATE& state);
// 合并输入变化
virtual bool OnMergeChangeDpadUp(const INPUT_EVENT_STATE& state);
virtual bool OnMergeChangeDpadDown(const INPUT_EVENT_STATE& state);
virtual bool OnMergeChangeDpadLeft(const INPUT_EVENT_STATE& state);
virtual bool OnMergeChangeDpadRight(const INPUT_EVENT_STATE& state);
virtual bool OnMergeChangeBack(const INPUT_EVENT_STATE& state);
virtual bool OnMergeChangeStart(const INPUT_EVENT_STATE& state);
virtual bool OnMergeChangeGuide(const INPUT_EVENT_STATE& state);
virtual bool OnMergeChangeShare(const INPUT_EVENT_STATE& state);
virtual bool OnMergeChangeA(const INPUT_EVENT_STATE& state);
virtual bool OnMergeChangeB(const INPUT_EVENT_STATE& state);
virtual bool OnMergeChangeX(const INPUT_EVENT_STATE& state);
virtual bool OnMergeChangeY(const INPUT_EVENT_STATE& state);
virtual bool OnMergeChangeLeftShoulder(const INPUT_EVENT_STATE& state);
virtual bool OnMergeChangeRightShoulder(const INPUT_EVENT_STATE& state);
virtual bool OnMergeChangeLeftTrigger(const INPUT_EVENT_STATE& state);
virtual bool OnMergeChangeRightTrigger(const INPUT_EVENT_STATE& state);
virtual bool OnMergeChangeLeftStick(const INPUT_EVENT_STATE& state);
virtual bool OnMergeChangeRightStick(const INPUT_EVENT_STATE& state);
virtual bool OnMergeChangeLeftThumb(const INPUT_EVENT_STATE& state);
virtual bool OnMergeChangeRightThumb(const INPUT_EVENT_STATE& state);
private:
// 任务循环
void _GamepadLoop();
// 睡眠间隔
void _Sleep(int millisecond);
// 更新扳机状态
void _UpdateTriggerState(INPUT_EVENT_STATE& state, BYTE bCurTrigger, BYTE bLastTrigger);
// 更新摇杆按钮
void _UpdateStickButton(GAME_PAD_BUTTON_INFO& curStick, GAME_PAD_BUTTON_INFO& lastStick);
// 更新摇杆方向状态
void _UpdateStickDirection(INPUT_EVENT_STATE& state, GAME_PAD_STICK_DIRECTION& curStick, GAME_PAD_STICK_DIRECTION& lastStick, SHORT sCurX, SHORT sCurY);
// 按钮状态变化处理
void _UpateButtonState(INPUT_EVENT_STATE& state, const XINPUT_GAMEPAD& cur, const XINPUT_GAMEPAD& last, DWORD wButton);
// 状态变化输入处理
void _InputChangeProcess(DWORD dwIndex);
// 混合输入处理
void _InputMergeProcess();
// 混合输入变化处理
void _InputMergeChangeProcess();
private:
std::function<void(DWORD dwIndex, const XINPUT_GAMEPAD& xGamepad)> m_cbRawState; // 检测每个控制器输入数据回调
std::function<void(const XINPUT_GAMEPAD& xGamepad)> m_cbMergeState; // 合并多个控制器输入数据回调
std::function<void(const INPUT_EVENT_STATE& state)> m_cbRawChange; // 检测每个控制器输入状态变化回调(发生按钮按下, 释放, 按住时触发)
std::function<void(const INPUT_EVENT_STATE& state)> m_cbMergeChange; // 合并多个控制器输入状态变化回调(发生按钮按下, 释放, 按住时触发)
std::map<DWORD, INPUT_EVENT_INFO> m_buttonEvents[XUSER_MAX_COUNT];
std::map<DWORD, INPUT_EVENT_INFO> m_mergeEvents;
std::thread m_gamepadTask; // 控制器状态检测任务线程
int m_LeftThumbThreshold; // 左摇杆触发阈值
int m_RightThumbThreshold; // 右摇杆触发阈值
int m_DataInterval; // 采集间隔时间
bool m_bIgnoreLeftThumbEmpty; // 左摇杆 X,Y 轴数据均为 0 时也触发回调
bool m_bIgnoreRightThumbEmpty; // 右摇杆 X,Y 轴数据均为 0 时也触发回调
bool m_fQuit; // 退出标志
public:
XINPUT_STATE m_CurXInputState[XUSER_MAX_COUNT]; // 当前控制器输入状态
XINPUT_STATE m_LastXInputState[XUSER_MAX_COUNT]; // 上次控制器输入状态
XINPUT_STATE m_CurXInputMerge; // 当前全部控制器混合输入状态
XINPUT_STATE m_LastXInputMerge; // 当前全部控制器混合输入状态
GAME_PAD_BUTTON_MASK m_CurButtonState[XUSER_MAX_COUNT];
GAME_PAD_BUTTON_MASK m_CurButtonMerge;
};
CXinputHelper.cpp
#include "CXInputHelper.h"
#include <stdint.h>
#include <Winerror.h>
#include <map>
#include <math.h>
//#pragma comment(lib, "Winmm.lib")
void CXInputHelper::_Sleep(int millisecond)
{
//timeBeginPeriod(1);
do
{
const int span = 1;
if (millisecond < span)
{
std::this_thread::sleep_for(std::chrono::milliseconds(millisecond));
return;
}
clock_t tmBegin = clock();
while (true)
{
if (clock() - tmBegin > millisecond)
{
break;
}
if (m_fQuit)
{
break;
}
std::this_thread::sleep_for(std::chrono::milliseconds(span));
}
} while (false);
//timeEndPeriod(1);
}
void CXInputHelper::PrintText(LPCTSTR pFormat, ...)
{
size_t nCchCount = MAX_PATH;
_tstring strResult(nCchCount, 0);
va_list args;
va_start(args, pFormat);
do
{
//格式化输出字符串
int nSize = _vsntprintf_s(&strResult[0], nCchCount, _TRUNCATE, pFormat, args);
if (-1 != nSize)
{
HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
::WriteConsole(console, strResult.c_str(), nSize, NULL, NULL);
break;
}
//缓冲大小超限终止
if (nCchCount >= INT32_MAX)
{
break;
}
//重新分配缓冲
nCchCount *= 2;
strResult.resize(nCchCount);
} while (true);
va_end(args);
}
CXInputHelper::CXInputHelper()
:
m_bIgnoreLeftThumbEmpty(true),
m_bIgnoreRightThumbEmpty(true),
m_fQuit(false),
m_LeftThumbThreshold(0),
m_RightThumbThreshold(0),
m_DataInterval(10)
{
memset(&m_CurXInputState, 0, sizeof(m_CurXInputState));
memset(&m_LastXInputState, 0, sizeof(m_LastXInputState));
memset(&m_CurXInputMerge, 0, sizeof(m_CurXInputMerge));
memset(&m_LastXInputMerge, 0, sizeof(m_LastXInputMerge));
memset(&m_CurButtonState, 0, sizeof(m_CurButtonState));
memset(&m_CurButtonMerge, 0, sizeof(m_CurButtonMerge));
}
CXInputHelper::~CXInputHelper()
{
Uninitialize();
}
bool CXInputHelper::Initialize()
{
Uninitialize();
m_gamepadTask = std::move(std::thread([this]() {
_GamepadLoop();
}));
return true;
}
void CXInputHelper::Uninitialize()
{
if (m_gamepadTask.joinable())
{
m_fQuit = true;
m_gamepadTask.join();
}
m_fQuit = false;
}
void CXInputHelper::IgnoreLeftThumbEmpty(
bool bEnable
)
{
m_bIgnoreLeftThumbEmpty = bEnable;
}
void CXInputHelper::IgnoreRightThumbEmpty(
bool bEnable
)
{
m_bIgnoreRightThumbEmpty = bEnable;
}
void CXInputHelper::SetInterval(
int millisecond
)
{
m_DataInterval = millisecond;
}
void CXInputHelper::SetThumbThreshold(
int nLeftThumbThreshold/* = 4096*/,
int nRightThumbThreshold/* = 4096*/
)
{
m_LeftThumbThreshold = nLeftThumbThreshold;
m_RightThumbThreshold = nRightThumbThreshold;
}
void CXInputHelper::SetRawStateCallback(
std::function<void(
DWORD dwIndex,
const XINPUT_GAMEPAD& xGamepad
)> cb
)
{
m_cbRawState = cb;
}
void CXInputHelper::SetMergeStateCallback(
std::function<void(
const XINPUT_GAMEPAD& xGamepad
)> cb
)
{
m_cbMergeState = cb;
}
void CXInputHelper::SetRawChangeCallback(
std::function<void(
const INPUT_EVENT_STATE& state
)> cb
)
{
m_cbRawChange = cb;
}
void CXInputHelper::SetMergeChangeCallback(
std::function<void(
const INPUT_EVENT_STATE& state
)> cb
)
{
m_cbMergeChange = cb;
}
// 输入变化
bool CXInputHelper::OnChangeDpadUp(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnChangeDpadDown(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnChangeDpadLeft(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnChangeDpadRight(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnChangeBack(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnChangeStart(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnChangeGuide(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnChangeShare(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnChangeA(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnChangeB(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnChangeX(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnChangeY(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnChangeLeftShoulder(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnChangeRightShoulder(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnChangeLeftTrigger(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnChangeRightTrigger(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnChangeLeftStick(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnChangeRightStick(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnChangeLeftThumb(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnChangeRightThumb(const INPUT_EVENT_STATE& state)
{
return true;
}
// 合并输入变化
bool CXInputHelper::OnMergeChangeDpadUp(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnMergeChangeDpadDown(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnMergeChangeDpadLeft(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnMergeChangeDpadRight(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnMergeChangeBack(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnMergeChangeStart(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnMergeChangeGuide(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnMergeChangeShare(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnMergeChangeA(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnMergeChangeB(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnMergeChangeX(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnMergeChangeY(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnMergeChangeLeftShoulder(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnMergeChangeRightShoulder(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnMergeChangeLeftTrigger(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnMergeChangeRightTrigger(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnMergeChangeLeftStick(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnMergeChangeRightStick(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnMergeChangeLeftThumb(const INPUT_EVENT_STATE& state)
{
return true;
}
bool CXInputHelper::OnMergeChangeRightThumb(const INPUT_EVENT_STATE& state)
{
return true;
}
void CXInputHelper::PrintState(const INPUT_EVENT_STATE& state)
{
PrintText(_T("OnRightThumb Index: %d bRight: %d Trigger: %3d %6d,%6d Button: %04X Press: %d Release: %d Holding: %d Time:%08d, Duration: %08d\r\n"),
state.dwIndex,
state.fRight,
state.bTrigger,
state.sThumbX, state.sThumbY,
state.dwButtons,
state.curButtonFlag.Mask.Down,
state.curButtonFlag.Mask.Up,
state.curButtonFlag.Mask.Hold,
state.dwTime,
state.dwDuration
);
}
void CXInputHelper::_GamepadLoop()
{
m_buttonEvents[0] = {
{XINPUT_GAMEPAD_A, INPUT_EVENT_INFO(&CXInputHelper::OnChangeA)},
{XINPUT_GAMEPAD_B, INPUT_EVENT_INFO(&CXInputHelper::OnChangeB)},
{XINPUT_GAMEPAD_X, INPUT_EVENT_INFO(&CXInputHelper::OnChangeX)},
{XINPUT_GAMEPAD_Y, INPUT_EVENT_INFO(&CXInputHelper::OnChangeY)},
{XINPUT_GAMEPAD_BACK, INPUT_EVENT_INFO(&CXInputHelper::OnChangeBack)},
{XINPUT_GAMEPAD_START, INPUT_EVENT_INFO(&CXInputHelper::OnChangeStart)},
{XINPUT_GAMEPAD_GUIDE, INPUT_EVENT_INFO(&CXInputHelper::OnChangeGuide)},
{XINPUT_GAMEPAD_SHARE, INPUT_EVENT_INFO(&CXInputHelper::OnChangeShare)},
{XINPUT_GAMEPAD_DPAD_UP, INPUT_EVENT_INFO(&CXInputHelper::OnChangeDpadUp)},
{XINPUT_GAMEPAD_DPAD_DOWN, INPUT_EVENT_INFO(&CXInputHelper::OnChangeDpadDown)},
{XINPUT_GAMEPAD_DPAD_LEFT, INPUT_EVENT_INFO(&CXInputHelper::OnChangeDpadLeft)},
{XINPUT_GAMEPAD_DPAD_RIGHT, INPUT_EVENT_INFO(&CXInputHelper::OnChangeDpadRight)},
{XINPUT_GAMEPAD_LEFT_SHOULDER, INPUT_EVENT_INFO(&CXInputHelper::OnChangeLeftShoulder)},
{XINPUT_GAMEPAD_RIGHT_SHOULDER, INPUT_EVENT_INFO(&CXInputHelper::OnChangeRightShoulder)},
{XINPUT_GAMEPAD_LEFT_THUMB, INPUT_EVENT_INFO(&CXInputHelper::OnChangeLeftThumb)},
{XINPUT_GAMEPAD_RIGHT_THUMB, INPUT_EVENT_INFO(&CXInputHelper::OnChangeRightThumb)},
{XINPUT_GAMEPAD_LEFT_TRIGGER, INPUT_EVENT_INFO(&CXInputHelper::OnChangeLeftTrigger)},
{XINPUT_GAMEPAD_RIGHT_TRIGGER, INPUT_EVENT_INFO(&CXInputHelper::OnChangeRightTrigger)},
{XINPUT_GAMEPAD_LEFT_STICK, INPUT_EVENT_INFO(&CXInputHelper::OnChangeLeftStick)},
{XINPUT_GAMEPAD_RIGHT_STICK, INPUT_EVENT_INFO(&CXInputHelper::OnChangeRightStick)}
};
m_buttonEvents[1] = m_buttonEvents[0];
m_buttonEvents[2] = m_buttonEvents[0];
m_buttonEvents[3] = m_buttonEvents[0];
m_mergeEvents = {
{XINPUT_GAMEPAD_A, INPUT_EVENT_INFO(&CXInputHelper::OnMergeChangeA)},
{XINPUT_GAMEPAD_B, INPUT_EVENT_INFO(&CXInputHelper::OnMergeChangeB)},
{XINPUT_GAMEPAD_X, INPUT_EVENT_INFO(&CXInputHelper::OnMergeChangeX)},
{XINPUT_GAMEPAD_Y, INPUT_EVENT_INFO(&CXInputHelper::OnMergeChangeY)},
{XINPUT_GAMEPAD_BACK, INPUT_EVENT_INFO(&CXInputHelper::OnMergeChangeBack)},
{XINPUT_GAMEPAD_START, INPUT_EVENT_INFO(&CXInputHelper::OnMergeChangeStart)},
{XINPUT_GAMEPAD_GUIDE, INPUT_EVENT_INFO(&CXInputHelper::OnMergeChangeGuide)},
{XINPUT_GAMEPAD_SHARE, INPUT_EVENT_INFO(&CXInputHelper::OnMergeChangeShare)},
{XINPUT_GAMEPAD_DPAD_UP, INPUT_EVENT_INFO(&CXInputHelper::OnMergeChangeDpadUp)},
{XINPUT_GAMEPAD_DPAD_DOWN, INPUT_EVENT_INFO(&CXInputHelper::OnMergeChangeDpadDown)},
{XINPUT_GAMEPAD_DPAD_LEFT, INPUT_EVENT_INFO(&CXInputHelper::OnMergeChangeDpadLeft)},
{XINPUT_GAMEPAD_DPAD_RIGHT, INPUT_EVENT_INFO(&CXInputHelper::OnMergeChangeDpadRight)},
{XINPUT_GAMEPAD_LEFT_SHOULDER, INPUT_EVENT_INFO(&CXInputHelper::OnMergeChangeLeftShoulder)},
{XINPUT_GAMEPAD_RIGHT_SHOULDER, INPUT_EVENT_INFO(&CXInputHelper::OnMergeChangeRightShoulder)},
{XINPUT_GAMEPAD_LEFT_THUMB, INPUT_EVENT_INFO(&CXInputHelper::OnMergeChangeLeftThumb)},
{XINPUT_GAMEPAD_RIGHT_THUMB, INPUT_EVENT_INFO(&CXInputHelper::OnMergeChangeRightThumb)},
{XINPUT_GAMEPAD_LEFT_TRIGGER, INPUT_EVENT_INFO(&CXInputHelper::OnMergeChangeLeftTrigger)},
{XINPUT_GAMEPAD_RIGHT_TRIGGER, INPUT_EVENT_INFO(&CXInputHelper::OnMergeChangeRightTrigger)},
{XINPUT_GAMEPAD_LEFT_STICK, INPUT_EVENT_INFO(&CXInputHelper::OnMergeChangeLeftStick)},
{XINPUT_GAMEPAD_RIGHT_STICK, INPUT_EVENT_INFO(&CXInputHelper::OnMergeChangeRightStick)}
};
// 加载 控制器状态检测 函数
HMODULE hModule = LoadLibrary(_T("XInput1_4.dll"));
if (NULL == hModule) hModule = LoadLibrary(_T("xinput1_3.dll"));
if (NULL == hModule) return;
typedef int(__stdcall* _XInputGetStateEx)(DWORD dwUserIndex, XINPUT_STATE* pState);
_XInputGetStateEx XInputGetStateEx = (_XInputGetStateEx)::GetProcAddress(hModule, (LPCSTR)100);
if (nullptr == XInputGetStateEx)
{
XInputGetStateEx = (_XInputGetStateEx)::GetProcAddress(hModule, "XInputGetState");
}
clock_t tmCount = ::clock();
while (!m_fQuit && XInputGetStateEx)
{
// 遍历控制器输入
for (DWORD i = 0; i < XUSER_MAX_COUNT; ++i)
{
XINPUT_STATE xTmpState = { 0 };
DWORD dwResult = XInputGetStateEx(i, &xTmpState);
// 摇杆触发值限定
if (abs(xTmpState.Gamepad.sThumbLX) < m_LeftThumbThreshold) xTmpState.Gamepad.sThumbLX = 0;
if (abs(xTmpState.Gamepad.sThumbLY) < m_LeftThumbThreshold) xTmpState.Gamepad.sThumbLY = 0;
if (abs(xTmpState.Gamepad.sThumbRX) < m_RightThumbThreshold) xTmpState.Gamepad.sThumbRX = 0;
if (abs(xTmpState.Gamepad.sThumbRY) < m_RightThumbThreshold) xTmpState.Gamepad.sThumbRY = 0;
m_CurXInputState[i] = xTmpState;
// 原始数据回调
if (m_cbRawState)
{
m_cbRawState(i, xTmpState.Gamepad);
}
// 未连接控制器
if (ERROR_DEVICE_NOT_CONNECTED == dwResult)
{
m_LastXInputState[i] = m_CurXInputState[i];
continue;
}
// 单控制器输入变化处理
_InputChangeProcess(i);
}
// 混合输入处理
_InputMergeProcess();
// 混合输入变化处理
_InputMergeChangeProcess();
// 输入轮询间隔
while (clock() - tmCount < m_DataInterval)
{
_Sleep(1);
}
tmCount = clock();
}
if (hModule)
{
::FreeLibrary(hModule);
}
}
void CXInputHelper::_UpdateTriggerState(INPUT_EVENT_STATE& state, BYTE bCurTrigger, BYTE bLastTrigger)
{
clock_t curTime = ::clock();
if (0 == bLastTrigger && bCurTrigger)
{
state.curButtonFlag.Mask.Down = true;
state.dwTime = curTime;
state.dwDuration = 0;
}
if (bLastTrigger && 0 == bCurTrigger)
{
state.curButtonFlag.Mask.Up = true;
state.dwDuration = curTime - state.dwTime;
}
if (bLastTrigger && bCurTrigger)
{
state.curButtonFlag.Mask.Hold = true;
state.dwDuration = curTime - state.dwTime;
}
}
void CXInputHelper::_UpdateStickButton(GAME_PAD_BUTTON_INFO& curStick, GAME_PAD_BUTTON_INFO& lastStick)
{
clock_t curTime = ::clock();
curStick.Flag.Mask.Down = false;
curStick.Flag.Mask.Up = false;
curStick.Flag.Mask.Hold = false;
// 按下
if (curStick.Value && !lastStick.Value)
{
curStick.Flag.Mask.Down = true;
curStick.dwTime = curTime;
curStick.dwDuration = 0;
}
// 弹起
if (!curStick.Value && lastStick.Value)
{
curStick.Flag.Mask.Up = true;
curStick.dwDuration = curTime - curStick.dwTime;
}
// 按住
if (curStick.Value && lastStick.Value)
{
curStick.Flag.Mask.Hold = true;
curStick.dwDuration = curTime - curStick.dwTime;
}
// 无
if (!curStick.Value && !lastStick.Value)
{
curStick.dwTime = 0;
curStick.dwDuration = 0;
}
}
void CXInputHelper::_UpdateStickDirection(INPUT_EVENT_STATE& state, GAME_PAD_STICK_DIRECTION& curStick, GAME_PAD_STICK_DIRECTION& lastStick, SHORT sCurX, SHORT sCurY)
{
clock_t curTime = ::clock();
curStick.Direction.State = 0;
curStick.Up.Value = 0;
curStick.Down.Value = 0;
curStick.Left.Value = 0;
curStick.Right.Value = 0;
// 获取角度
double fCurAngle = atan2(sCurY, sCurX) * 180.0f / PI;
// 上
if (sCurY > m_LeftThumbThreshold)
{
if (fCurAngle >= (90.0f - ANGLE_RANGE) && fCurAngle <= (90.0f + ANGLE_RANGE))
{
curStick.Direction.Mask.Up = 1;
curStick.Up.Value = 1;
}
}
// 下
if (sCurY < -m_LeftThumbThreshold)
{
if (fCurAngle >= -(90.0f + ANGLE_RANGE) && fCurAngle <= -(90.0f - ANGLE_RANGE))
{
curStick.Direction.Mask.Down = 1;
curStick.Down.Value = 1;
}
}
// 左
if (sCurX < -m_LeftThumbThreshold)
{
if (fCurAngle >= (180.0f - ANGLE_RANGE) || fCurAngle <= -(180.0f - ANGLE_RANGE))
{
curStick.Left.Value = 1;
curStick.Direction.Mask.Left = 1;
}
}
// 右
if (sCurX > m_LeftThumbThreshold)
{
if (fCurAngle >= -ANGLE_RANGE && fCurAngle <= ANGLE_RANGE)
{
curStick.Direction.Mask.Right = 1;
curStick.Right.Value = 1;
}
}
// 右上
if (sCurX > m_LeftThumbThreshold && sCurY > m_LeftThumbThreshold)
{
if (fCurAngle > (45.0f - ANGLE_RANGE) && fCurAngle < (45.0f + ANGLE_RANGE))
{
curStick.Direction.Mask.Right = 1;
curStick.Direction.Mask.Up = 1;
curStick.Right.Value = 1;
curStick.Up.Value = 1;
}
}
// 左上
if (sCurX < -m_LeftThumbThreshold && sCurY > m_LeftThumbThreshold)
{
if (fCurAngle > (135.0f - ANGLE_RANGE) && fCurAngle < (135.0f + ANGLE_RANGE))
{
curStick.Direction.Mask.Left = 1;
curStick.Direction.Mask.Up = 1;
curStick.Left.Value = 1;
curStick.Up.Value = 1;
}
}
// 左下
if (sCurY < -m_LeftThumbThreshold && sCurX < -m_LeftThumbThreshold)
{
if (fCurAngle > -(135.0f + ANGLE_RANGE) && fCurAngle < -(135.0f - ANGLE_RANGE))
{
curStick.Direction.Mask.Left = 1;
curStick.Direction.Mask.Down = 1;
curStick.Left.Value = 1;
curStick.Down.Value = 1;
}
}
// 右下
if (sCurY < -m_LeftThumbThreshold && sCurX > m_LeftThumbThreshold)
{
if (fCurAngle > -(45.0f + ANGLE_RANGE) && fCurAngle < -(45.0f - ANGLE_RANGE))
{
curStick.Direction.Mask.Right = 1;
curStick.Direction.Mask.Down = 1;
curStick.Right.Value = 1;
curStick.Down.Value = 1;
}
}
// 按下
if (!lastStick.Direction.State && curStick.Direction.State)
{
state.curButtonFlag.Mask.Down = true;
state.dwTime = curTime;
state.dwDuration = 0;
}
// 弹起
if (lastStick.Direction.State && !curStick.Direction.State)
{
state.curButtonFlag.Mask.Up = true;
state.dwDuration = curTime - state.dwTime;
}
// 按住
if (lastStick.Direction.State && curStick.Direction.State)
{
state.curButtonFlag.Mask.Hold = true;
state.dwDuration = curTime - state.dwTime;
}
// 状态转换
_UpdateStickButton(curStick.Up, lastStick.Up);
_UpdateStickButton(curStick.Down, lastStick.Down);
_UpdateStickButton(curStick.Left, lastStick.Left);
_UpdateStickButton(curStick.Right, lastStick.Right);
}
void CXInputHelper::_UpateButtonState(INPUT_EVENT_STATE& state, const XINPUT_GAMEPAD& cur, const XINPUT_GAMEPAD& last, DWORD wButton) {
state.curButtonFlag.Mask.Down = false;
state.curButtonFlag.Mask.Up = false;
state.curButtonFlag.Mask.Hold = false;
// 左扳机
if (XINPUT_GAMEPAD_LEFT_TRIGGER == wButton)
{
_UpdateTriggerState(state, cur.bLeftTrigger, last.bLeftTrigger);
}
// 右扳机
else if (XINPUT_GAMEPAD_RIGHT_TRIGGER == wButton)
{
_UpdateTriggerState(state, cur.bRightTrigger, last.bRightTrigger);
}
// 左摇杆
else if (XINPUT_GAMEPAD_LEFT_STICK == wButton)
{
_UpdateStickDirection(state, state.curLeftStickDirection, state.lastLeftStickDirection, cur.sThumbLX, cur.sThumbLY);
state.buttonBitMask.Mask.LeftStickUp = state.curLeftStickDirection.Up.Value;
state.buttonBitMask.Mask.LeftStickDown = state.curLeftStickDirection.Down.Value;
state.buttonBitMask.Mask.LeftStickLeft = state.curLeftStickDirection.Left.Value;
state.buttonBitMask.Mask.LeftStickRight = state.curLeftStickDirection.Right.Value;
state.lastLeftStickDirection = state.curLeftStickDirection;
}
// 右摇杆
else if (XINPUT_GAMEPAD_RIGHT_STICK == wButton)
{
_UpdateStickDirection(state, state.curRightStickDirection, state.lastRightStickDirection, cur.sThumbRX, cur.sThumbRY);
state.buttonBitMask.Mask.RightStickUp = state.curRightStickDirection.Up.Value;
state.buttonBitMask.Mask.RightStickDown = state.curRightStickDirection.Down.Value;
state.buttonBitMask.Mask.RightStickLeft = state.curRightStickDirection.Left.Value;
state.buttonBitMask.Mask.RightStickRight = state.curRightStickDirection.Right.Value;
state.lastRightStickDirection = state.curRightStickDirection;
}
else
{
clock_t curTime = ::clock();
// 按下
if ((0 == (last.wButtons & wButton)) && (cur.wButtons & wButton))
{
state.curButtonFlag.Mask.Down = true;
state.dwTime = curTime;
state.dwDuration = 0;
}
// 弹起
if ((last.wButtons & wButton) && (0 == (cur.wButtons & wButton)))
{
state.curButtonFlag.Mask.Up = true;
state.dwDuration = curTime - state.dwTime;
}
// 按住
if ((last.wButtons & wButton) && (cur.wButtons & wButton))
{
state.curButtonFlag.Mask.Hold = true;
state.dwDuration = curTime - state.dwTime;
}
}
}
void CXInputHelper::_InputChangeProcess(DWORD dwIndex)
{
// 状态处理
for (auto& item : m_buttonEvents[dwIndex])
{
INPUT_EVENT_INFO& eventInfo = item.second;
// 按钮状态变化处理
_UpateButtonState(eventInfo.eventState, m_CurXInputState[dwIndex].Gamepad, m_LastXInputState[dwIndex].Gamepad, item.first);
}
// 得到全部输入状态
m_CurButtonState[dwIndex].dwButtons = 0;
for (auto& item : m_buttonEvents[dwIndex])
{
INPUT_EVENT_INFO& eventInfo = item.second;
if (XINPUT_GAMEPAD_LEFT_TRIGGER == item.first)
{
m_CurButtonState[dwIndex].Mask.LeftTrigger = eventInfo.eventState.curButtonFlag.Mask.Down || eventInfo.eventState.curButtonFlag.Mask.Hold;
}
else if (XINPUT_GAMEPAD_RIGHT_TRIGGER == item.first)
{
eventInfo.eventState.fRight = true;
m_CurButtonState[dwIndex].Mask.RightTrigger = eventInfo.eventState.curButtonFlag.Mask.Down || eventInfo.eventState.curButtonFlag.Mask.Hold;
}
else if (XINPUT_GAMEPAD_LEFT_STICK == item.first)
{
m_CurButtonState[dwIndex].Mask.LeftStickUp = eventInfo.eventState.buttonBitMask.Mask.LeftStickUp;
m_CurButtonState[dwIndex].Mask.LeftStickDown = eventInfo.eventState.buttonBitMask.Mask.LeftStickDown;
m_CurButtonState[dwIndex].Mask.LeftStickLeft = eventInfo.eventState.buttonBitMask.Mask.LeftStickLeft;
m_CurButtonState[dwIndex].Mask.LeftStickRight = eventInfo.eventState.buttonBitMask.Mask.LeftStickRight;
}
else if (XINPUT_GAMEPAD_RIGHT_STICK == item.first)
{
eventInfo.eventState.fRight = true;
m_CurButtonState[dwIndex].Mask.RightStickUp = eventInfo.eventState.buttonBitMask.Mask.RightStickUp;
m_CurButtonState[dwIndex].Mask.RightStickDown = eventInfo.eventState.buttonBitMask.Mask.RightStickDown;
m_CurButtonState[dwIndex].Mask.RightStickLeft = eventInfo.eventState.buttonBitMask.Mask.RightStickLeft;
m_CurButtonState[dwIndex].Mask.RightStickRight = eventInfo.eventState.buttonBitMask.Mask.RightStickRight;
}
else
{
m_CurButtonState[dwIndex].dwButtons |= (eventInfo.eventState.curButtonFlag.Mask.Down || eventInfo.eventState.curButtonFlag.Mask.Hold) ? item.first : 0;
}
}
// 回调处理
for (auto& item : m_buttonEvents[dwIndex])
{
INPUT_EVENT_INFO& eventInfo = item.second;
eventInfo.eventState.dwButtonMask = item.first;
eventInfo.eventState.dwIndex = dwIndex;
eventInfo.eventState.buttonBitMask.dwButtons = m_CurButtonState[dwIndex].dwButtons;
eventInfo.eventState.dwButtons = m_CurButtonState[dwIndex].dwButtons;
if (eventInfo.eventState.curButtonFlag.State)
{
eventInfo.eventState.xinputState = m_CurXInputState[dwIndex];
if (XINPUT_GAMEPAD_LEFT_TRIGGER == item.first)
{
eventInfo.eventState.bTrigger = m_CurXInputState[dwIndex].Gamepad.bLeftTrigger;
}
if (XINPUT_GAMEPAD_RIGHT_TRIGGER == item.first)
{
eventInfo.eventState.fRight = true;
eventInfo.eventState.bTrigger = m_CurXInputState[dwIndex].Gamepad.bRightTrigger;
}
if (XINPUT_GAMEPAD_LEFT_STICK == item.first)
{
eventInfo.eventState.sThumbX = m_CurXInputState[dwIndex].Gamepad.sThumbLX;
eventInfo.eventState.sThumbY = m_CurXInputState[dwIndex].Gamepad.sThumbLY;
eventInfo.eventState.stickDirection = eventInfo.eventState.curLeftStickDirection;
}
if (XINPUT_GAMEPAD_RIGHT_STICK == item.first)
{
eventInfo.eventState.fRight = true;
eventInfo.eventState.sThumbX = m_CurXInputState[dwIndex].Gamepad.sThumbRX;
eventInfo.eventState.sThumbY = m_CurXInputState[dwIndex].Gamepad.sThumbRY;
eventInfo.eventState.stickDirection = eventInfo.eventState.curRightStickDirection;
}
(this->*(eventInfo.eventCb))(eventInfo.eventState);
if (m_cbRawChange)
{
m_cbRawChange(eventInfo.eventState);
}
}
}
m_LastXInputState[dwIndex] = m_CurXInputState[dwIndex];
}
void CXInputHelper::_InputMergeProcess()
{
LONG nThumbLX = 0;
LONG nThumbLY = 0;
LONG nThumbRX = 0;
LONG nThumbRY = 0;
LONG nLeftTrigger = 0;
LONG nRightTrigger = 0;
// 混合输入按钮状态
m_CurXInputMerge.Gamepad.wButtons = 0;
for (DWORD i = 0; i < XUSER_MAX_COUNT; ++i)
{
m_CurXInputMerge.Gamepad.wButtons |= m_CurXInputState[i].Gamepad.wButtons;
nThumbLX += m_CurXInputState[i].Gamepad.sThumbLX;
nThumbLY += m_CurXInputState[i].Gamepad.sThumbLY;
nThumbRX += m_CurXInputState[i].Gamepad.sThumbRX;
nThumbRY += m_CurXInputState[i].Gamepad.sThumbRY;
nLeftTrigger += m_CurXInputState[i].Gamepad.bLeftTrigger;
nRightTrigger += m_CurXInputState[i].Gamepad.bRightTrigger;
}
if (nLeftTrigger > UINT8_MAX) nLeftTrigger = UINT8_MAX;
if (nRightTrigger > UINT8_MAX) nRightTrigger = UINT8_MAX;
if (nThumbLX < INT16_MIN) nThumbLX = INT16_MIN;
if (nThumbLY < INT16_MIN) nThumbLY = INT16_MIN;
if (nThumbRX < INT16_MIN) nThumbRX = INT16_MIN;
if (nThumbRY < INT16_MIN) nThumbRY = INT16_MIN;
if (nThumbLX > INT16_MAX) nThumbLX = INT16_MAX;
if (nThumbLY > INT16_MAX) nThumbLY = INT16_MAX;
if (nThumbRX > INT16_MAX) nThumbRX = INT16_MAX;
if (nThumbRY > INT16_MAX) nThumbRY = INT16_MAX;
m_CurXInputMerge.Gamepad.bLeftTrigger = nLeftTrigger;
m_CurXInputMerge.Gamepad.bRightTrigger = nRightTrigger;
m_CurXInputMerge.Gamepad.sThumbLX = nThumbLX;
m_CurXInputMerge.Gamepad.sThumbLY = nThumbLY;
m_CurXInputMerge.Gamepad.sThumbRX = nThumbRX;
m_CurXInputMerge.Gamepad.sThumbRY = nThumbRY;
if (m_cbMergeState)
{
m_cbMergeState(m_CurXInputMerge.Gamepad);
}
}
void CXInputHelper::_InputMergeChangeProcess()
{
// 状态处理
for (auto& item : m_mergeEvents)
{
INPUT_EVENT_INFO& eventInfo = item.second;
// 按钮状态变化处理
_UpateButtonState(eventInfo.eventState, m_CurXInputMerge.Gamepad, m_LastXInputMerge.Gamepad, item.first);
}
// 得到全部输入状态
m_CurButtonMerge.dwButtons = 0;
for (auto& item : m_mergeEvents)
{
INPUT_EVENT_INFO& eventInfo = item.second;
if (XINPUT_GAMEPAD_LEFT_TRIGGER == item.first)
{
m_CurButtonMerge.Mask.LeftTrigger = eventInfo.eventState.curButtonFlag.Mask.Down || eventInfo.eventState.curButtonFlag.Mask.Hold;
}
else if (XINPUT_GAMEPAD_RIGHT_TRIGGER == item.first)
{
eventInfo.eventState.fRight = true;
m_CurButtonMerge.Mask.RightTrigger = eventInfo.eventState.curButtonFlag.Mask.Down || eventInfo.eventState.curButtonFlag.Mask.Hold;
}
else if (XINPUT_GAMEPAD_LEFT_STICK == item.first)
{
m_CurButtonMerge.Mask.LeftStickUp = eventInfo.eventState.buttonBitMask.Mask.LeftStickUp;
m_CurButtonMerge.Mask.LeftStickDown = eventInfo.eventState.buttonBitMask.Mask.LeftStickDown;
m_CurButtonMerge.Mask.LeftStickLeft = eventInfo.eventState.buttonBitMask.Mask.LeftStickLeft;
m_CurButtonMerge.Mask.LeftStickRight = eventInfo.eventState.buttonBitMask.Mask.LeftStickRight;
}
else if (XINPUT_GAMEPAD_RIGHT_STICK == item.first)
{
eventInfo.eventState.fRight = true;
m_CurButtonMerge.Mask.RightStickUp = eventInfo.eventState.buttonBitMask.Mask.RightStickUp;
m_CurButtonMerge.Mask.RightStickDown = eventInfo.eventState.buttonBitMask.Mask.RightStickDown;
m_CurButtonMerge.Mask.RightStickLeft = eventInfo.eventState.buttonBitMask.Mask.RightStickLeft;
m_CurButtonMerge.Mask.RightStickRight = eventInfo.eventState.buttonBitMask.Mask.RightStickRight;
eventInfo.eventState.sThumbX = m_CurXInputMerge.Gamepad.sThumbRX;
eventInfo.eventState.sThumbY = m_CurXInputMerge.Gamepad.sThumbRY;
}
else
{
m_CurButtonMerge.dwButtons |= eventInfo.eventState.curButtonFlag.Mask.Down || eventInfo.eventState.curButtonFlag.Mask.Hold ? item.first : 0;
}
}
// 回调处理
for (auto& item : m_mergeEvents)
{
INPUT_EVENT_INFO& eventInfo = item.second;
eventInfo.eventState.dwButtonMask = item.first;
eventInfo.eventState.buttonBitMask.dwButtons = m_CurButtonMerge.dwButtons;
eventInfo.eventState.dwButtons = m_CurButtonMerge.dwButtons;
if (XINPUT_GAMEPAD_LEFT_STICK == item.first)
{
eventInfo.eventState.sThumbX = m_CurXInputMerge.Gamepad.sThumbLX;
eventInfo.eventState.sThumbY = m_CurXInputMerge.Gamepad.sThumbLY;
}
if (XINPUT_GAMEPAD_RIGHT_STICK == item.first)
{
eventInfo.eventState.sThumbX = m_CurXInputMerge.Gamepad.sThumbRX;
eventInfo.eventState.sThumbY = m_CurXInputMerge.Gamepad.sThumbRY;
}
if (eventInfo.eventState.curButtonFlag.State)
{
eventInfo.eventState.xinputState = m_CurXInputMerge;
if (XINPUT_GAMEPAD_LEFT_TRIGGER == item.first)
{
eventInfo.eventState.bTrigger = m_CurXInputMerge.Gamepad.bLeftTrigger;
}
if (XINPUT_GAMEPAD_RIGHT_TRIGGER == item.first)
{
eventInfo.eventState.fRight = true;
eventInfo.eventState.bTrigger = m_CurXInputMerge.Gamepad.bRightTrigger;
eventInfo.eventState.stickDirection = eventInfo.eventState.curLeftStickDirection;
}
if (XINPUT_GAMEPAD_LEFT_STICK == item.first)
{
eventInfo.eventState.sThumbX = m_CurXInputMerge.Gamepad.sThumbLX;
eventInfo.eventState.sThumbY = m_CurXInputMerge.Gamepad.sThumbLY;
eventInfo.eventState.stickDirection = eventInfo.eventState.curRightStickDirection;
}
if (XINPUT_GAMEPAD_RIGHT_STICK == item.first)
{
eventInfo.eventState.fRight = true;
eventInfo.eventState.sThumbX = m_CurXInputMerge.Gamepad.sThumbRX;
eventInfo.eventState.sThumbY = m_CurXInputMerge.Gamepad.sThumbRY;
}
(this->*(eventInfo.eventCb))(eventInfo.eventState);
if (m_cbMergeChange)
{
m_cbMergeChange(eventInfo.eventState);
}
}
}
m_LastXInputMerge = m_CurXInputMerge;
}
main.cpp
// JoystickAssistant.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <string>
#include <iostream>
#include <windows.h>
#include <tchar.h>
#include "CWin32Utils/CXinputHelper.h"
#include "CWin32Utils/CInputUtils.h"
#include "CMainFrame.h"
#include "resource.h"
#ifdef _UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endif
void LogPrintf(LPCTSTR pFormat, ...);
int WINAPI WinMain(
_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,
_In_ int nShowCmd)
{
UNREFERENCED_PARAMETER(hInstance);
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
UNREFERENCED_PARAMETER(nShowCmd);
CMainFrame dlg;
dlg.DoModalEx(IDD_DIALOG_MAIN, NULL, TRUE, true);
return 0;
}
int main()
{
CXInputHelper obj;
obj.Initialize();
obj.IgnoreLeftThumbEmpty(false);
obj.IgnoreRightThumbEmpty(false);
obj.SetThumbThreshold(4096);
obj.SetMergeStateCallback([](const XINPUT_GAMEPAD& state)-> void {
/*LogPrintf(_T("Button: %04X\r\n"),
state.wButtons
);*/
}
);
obj.SetRawChangeCallback([](const INPUT_EVENT_STATE& state)-> void {
LogPrintf(_T("Mask: %08X bRight: %d Trigger: %3d Thumb: %6d,%6d State: %d Buttons: %.8X Duration: %6d L: %d U: %d R: %d D: %d\r\n"),
state.dwButtonMask,
state.fRight, state.bTrigger, state.sThumbX, state.sThumbY,
state.curButtonFlag.State,
state.dwButtons,
state.dwDuration,
state.stickDirection.Left.Flag.State,
state.stickDirection.Up.Flag.State,
state.stickDirection.Right.Flag.State,
state.stickDirection.Down.Flag.State
);
}
);
/*obj.SetMergeChangeCallback([](const XINPUT_GAMEPAD& xGamepad, const INPUT_EVENT_STATE& state)-> void {
LogPrintf(_T("Index: %d bRight: %d Trigger: %3d Thumb: %6d,%6d Button: %04X State: %04X Buttons: %.8X\r\n"),
state.dwIndex,
state.fRight, state.bTrigger, state.sThumbX, state.sThumbY,
state.wButton, state.curButtonFlag.State,
state.allButtonState.Buttons
);
}
);*/
system("pause");
return 0;
}
void LogPrintf(LPCTSTR pFormat, ...)
{
size_t nCchCount = MAX_PATH;
_tstring strResult(nCchCount, 0);
va_list args;
va_start(args, pFormat);
do
{
//格式化输出字符串
int nSize = _vsntprintf_s(&strResult[0], nCchCount, _TRUNCATE, pFormat, args);
if (-1 != nSize)
{
HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);
::WriteConsole(console, strResult.c_str(), nSize, NULL, NULL);
break;
}
//缓冲大小超限终止
if (nCchCount >= INT32_MAX)
{
break;
}
//重新分配缓冲
nCchCount *= 2;
strResult.resize(nCchCount);
} while (true);
va_end(args);
}
测试