CXinputHelper.h
#pragma once
#include <windows.h>
#include <xinput.h>
#include <tchar.h>
#include <thread>
#include <functional>
#include <string>
#pragma comment(lib, "xinput.lib")
#ifdef _UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endif
// 单个变化状态
typedef struct _GAMEPAD_INFO
{
DWORD dwIndex; // 当前手柄索引
WORD wButton; // 当前触发的单个按键
SHORT sThumbX; // 当前摇杆X值
SHORT sThumbY; // 当前摇杆Y值
BYTE bTrigger; // 扳机数据
bool bRight; // 是否为右摇杆/扳机(false: 左, true: 右)
bool bPress; // 是否触发按钮按下(从未按下 -> 按下)
bool bRelease; // 是否触发按钮释放(从按下 -> 未按下)
bool bHolding; // 按住触发按钮按住(从按下 -> 按下)
}GAMEPAD_INFO;
class CXInputHelper
{
public:
CXInputHelper();
virtual ~CXInputHelper();
bool Initialize();
void Uninitialize();
void IgnoreLeftThumbEmpty(
bool bEnable = true // 允许空数据触发回调
);
void IgnoreRightThumbEmpty(
bool bEnable = true // 允许空数据触发回调
);
void SetThumbThreshold(
int nThumbThreshold = 500 // 摇杆触发阈值(死区)
);
// 设置检测每个控制器输入数据回调
void SetSingleStateCallback(
std::function<void(
DWORD dwIndex, // 控制器索引(有效值: 0 - 3)
const XINPUT_GAMEPAD& xGamepad // 控制器数据
)> cb
);
// 设置合并多个控制器输入数据回调
void SetMergeStateCallback(
std::function<void(
const XINPUT_GAMEPAD& xGamepad // 控制器数据
)> cb
);
// 设置检测每个控制器输入状态变化回调(发生按钮按下, 释放, 按住时触发)
void SetSingleChangeCallback(
std::function<void(
const XINPUT_GAMEPAD& xGamepad, // 原始控制器数据
const GAMEPAD_INFO& state // 回调信息
)> cb
);
// 设置合并多个控制器输入状态变化回调(发生按钮按下, 释放, 按住时触发)
void SetMergeChangeCallback(
std::function<void(
const XINPUT_GAMEPAD& xGamepad, // 原始控制器数据
const GAMEPAD_INFO& state // 回调信息
)> cb
);
// 方向键回调
virtual bool OnButtonDpadUp(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state);
virtual bool OnButtonDpadDown(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state);
virtual bool OnButtonDpadLeft(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state);
virtual bool OnButtonDpadRight(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state);
// 返回键, 开始键回调
virtual bool OnButtonBack(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state);
virtual bool OnButtonStart(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state);
// XYBA回调
virtual bool OnButtonA(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state);
virtual bool OnButtonB(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state);
virtual bool OnButtonX(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state);
virtual bool OnButtonY(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state);
// 肩键回调
virtual bool OnButtonLeftShoulder(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state);
virtual bool OnButtonRightShoulder(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state);
// 拇指按键回调
virtual bool OnButtonLeftThumb(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state);
virtual bool OnButtonRightThumb(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state);
// 扳机回调
virtual bool OnLeftTrigger(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state);
virtual bool OnRightTrigger(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state);
// 拇指摇杆回调
virtual bool OnLeftThumb(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state);
virtual bool OnRightThumb(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state);
// 打印状态信息
virtual void PrintState(const GAMEPAD_INFO& state);
// 打印
void PrintText(LPCTSTR pFormat, ...);
private:
// 任务循环
void _GamepadLoop();
// 睡眠间隔
void _Sleep(int millisecond);
private:
std::function<void(DWORD dwIndex, const XINPUT_GAMEPAD& xGamepad)> m_cbSingleState; // 检测每个控制器输入数据回调
std::function<void(const XINPUT_GAMEPAD& xGamepad)> m_cbMergeState; // 合并多个控制器输入数据回调
std::function<void(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state)> m_cbSingleChange; // 检测每个控制器输入状态变化回调(发生按钮按下, 释放, 按住时触发)
std::function<void(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state)> m_cbMergeChange; // 合并多个控制器输入状态变化回调(发生按钮按下, 释放, 按住时触发)
std::thread m_gamepadTask; // 控制器状态检测任务线程
int m_ThumbThreshold; // 摇杆触发阈值
bool m_bIgnoreLeftThumbEmpty; // 左摇杆 X,Y 轴数据均为 0 时也触发回调
bool m_bIgnoreRightThumbEmpty; // 右摇杆 X,Y 轴数据均为 0 时也触发回调
bool m_fQuit = false; // 退出标志
};
CXinputHelper.cpp
#include "CXinputHelper.h"
#include <stdint.h>
#include <Winerror.h>
#include <map>
CXInputHelper::CXInputHelper()
:
m_bIgnoreLeftThumbEmpty(true),
m_bIgnoreRightThumbEmpty(true),
m_fQuit(false),
m_ThumbThreshold(200)
{
}
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::SetThumbThreshold(
int nThumbThreshold/* = 500*/
)
{
m_ThumbThreshold = nThumbThreshold;
}
void CXInputHelper::SetSingleStateCallback(
std::function<void(
DWORD dwIndex,
const XINPUT_GAMEPAD& xGamepad
)> cb
)
{
m_cbSingleState = cb;
}
void CXInputHelper::SetMergeStateCallback(
std::function<void(
const XINPUT_GAMEPAD& xGamepad
)> cb
)
{
m_cbMergeState = cb;
}
void CXInputHelper::SetSingleChangeCallback(
std::function<void(
const XINPUT_GAMEPAD& xGamepad,
const GAMEPAD_INFO& state
)> cb
)
{
m_cbSingleChange = cb;
}
void CXInputHelper::SetMergeChangeCallback(
std::function<void(
const XINPUT_GAMEPAD& xGamepad,
const GAMEPAD_INFO& state
)> cb
)
{
m_cbMergeChange = cb;
}
void CXInputHelper::_Sleep(int millisecond)
{
const int span = 10;
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));
}
}
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);
}
void CXInputHelper::_GamepadLoop()
{
typedef bool (CXInputHelper::* pFn)(const XINPUT_GAMEPAD& data, const GAMEPAD_INFO& state);
static std::map<DWORD, pFn> buttonEvents = {
{XINPUT_GAMEPAD_A, &CXInputHelper::OnButtonA},
{XINPUT_GAMEPAD_B, &CXInputHelper::OnButtonB},
{XINPUT_GAMEPAD_X, &CXInputHelper::OnButtonX},
{XINPUT_GAMEPAD_Y, &CXInputHelper::OnButtonY},
{XINPUT_GAMEPAD_BACK, &CXInputHelper::OnButtonBack},
{XINPUT_GAMEPAD_START, &CXInputHelper::OnButtonStart},
{XINPUT_GAMEPAD_DPAD_UP, &CXInputHelper::OnButtonDpadUp},
{XINPUT_GAMEPAD_DPAD_DOWN, &CXInputHelper::OnButtonDpadDown},
{XINPUT_GAMEPAD_DPAD_LEFT, &CXInputHelper::OnButtonDpadLeft},
{XINPUT_GAMEPAD_DPAD_RIGHT, &CXInputHelper::OnButtonDpadRight},
{XINPUT_GAMEPAD_LEFT_SHOULDER, &CXInputHelper::OnButtonLeftShoulder},
{XINPUT_GAMEPAD_RIGHT_SHOULDER, &CXInputHelper::OnButtonRightShoulder},
{XINPUT_GAMEPAD_LEFT_THUMB, &CXInputHelper::OnButtonLeftThumb},
{XINPUT_GAMEPAD_RIGHT_THUMB, &CXInputHelper::OnButtonRightThumb}
};
XINPUT_STATE xLastStateArray[XUSER_MAX_COUNT] = { 0 };
XINPUT_STATE xLastStateMixed = { 0 };
LONG nLastThumbLX = 0;
LONG nLastThumbLY = 0;
LONG nLastThumbRX = 0;
LONG nLastThumbRY = 0;
LONG nLastLeftTrigger = 0;
LONG nLastRightTrigger = 0;
// 按钮检测
auto HitButtonState = [this](bool& bPress, bool& bRelease, bool& bHolding, const XINPUT_GAMEPAD& last, const XINPUT_GAMEPAD& cur, WORD wButton) {
bPress = false;
bRelease = false;
bHolding = false;
if ((0 == (last.wButtons & wButton)) && (cur.wButtons & wButton)) bPress = true;
if ((last.wButtons & wButton) && (0 == (cur.wButtons & wButton))) bRelease = true;
if ((last.wButtons & wButton) && (cur.wButtons & wButton)) bHolding = true;
};
// 扳机检测
auto HitTriggerState = [this](bool& bPress, bool& bRelease, bool& bHolding, const LONG& nTrigger, const LONG& nLastTrigger) {
bPress = false;
bRelease = false;
bHolding = false;
if (0 == nLastTrigger && nTrigger) bPress = true;
if (nLastTrigger && 0 == nTrigger) bRelease = true;
if (nLastTrigger && nTrigger) bHolding = true;
};
while (!m_fQuit)
{
XINPUT_STATE xCurStateArray[XUSER_MAX_COUNT] = { 0 };
XINPUT_STATE xCurStateMixed = { 0 };
LONG nThumbLX = 0;
LONG nThumbLY = 0;
LONG nThumbRX = 0;
LONG nThumbRY = 0;
LONG nLeftTrigger = 0;
LONG nRightTrigger = 0;
// 遍历控制器输入
for (int i = 0; i < XUSER_MAX_COUNT; ++i)
{
XINPUT_STATE xTmpState = { 0 };
DWORD dwResult = ::XInputGetState(i, &xTmpState);
//触发值限定
if (abs(xTmpState.Gamepad.sThumbLX) < m_ThumbThreshold) xTmpState.Gamepad.sThumbLX = 0;
if (abs(xTmpState.Gamepad.sThumbLY) < m_ThumbThreshold) xTmpState.Gamepad.sThumbLY = 0;
if (abs(xTmpState.Gamepad.sThumbRX) < m_ThumbThreshold) xTmpState.Gamepad.sThumbRX = 0;
if (abs(xTmpState.Gamepad.sThumbRY) < m_ThumbThreshold) xTmpState.Gamepad.sThumbRY = 0;
xCurStateArray[i] = xTmpState;
//未连接控制器
if (ERROR_DEVICE_NOT_CONNECTED == dwResult)
{
xLastStateArray[i] = xCurStateArray[i];
continue;
}
// 累加多输入数据
{
xCurStateMixed.Gamepad.wButtons |= xTmpState.Gamepad.wButtons;
nLeftTrigger += xTmpState.Gamepad.bLeftTrigger;
nRightTrigger += xTmpState.Gamepad.bRightTrigger;
nThumbLX += xTmpState.Gamepad.sThumbLX;
nThumbLY += xTmpState.Gamepad.sThumbLY;
nThumbRX += xTmpState.Gamepad.sThumbRX;
nThumbRY += xTmpState.Gamepad.sThumbRY;
}
//连接控制器
if (ERROR_SUCCESS == dwResult)
{
// 单控制器输入回调
if (m_cbSingleState)
{
m_cbSingleState(i, xTmpState.Gamepad);
}
// 单控制器变化回调
if (m_cbSingleChange)
{
XINPUT_GAMEPAD& lastState = xLastStateArray[i].Gamepad;
XINPUT_GAMEPAD& curState = xCurStateArray[i].Gamepad;
// 按键变化处理
for (const auto& item : buttonEvents)
{
GAMEPAD_INFO state = { 0 };
state.dwIndex = i;
bool bPress = false;
bool bRelease = false;
bool bHolding = false;
HitButtonState(bPress, bRelease, bHolding, lastState, curState, item.first);
if (bPress || bRelease || bHolding)
{
state.bPress = bPress;
state.bRelease = bRelease;
state.bHolding = bHolding;
state.wButton = item.first;
m_cbSingleChange(curState, state);
}
}
// 扳机变化处理
{
bool bPress = false;
bool bRelease = false;
bool bHolding = false;
// 左扳机
HitTriggerState(bPress, bRelease, bHolding, curState.bLeftTrigger, lastState.bLeftTrigger);
if (bPress || bRelease || bHolding)
{
GAMEPAD_INFO state = { 0 };
state.dwIndex = i;
state.bPress = bPress;
state.bRelease = bRelease;
state.bHolding = bHolding;
state.bRight = false;
state.bTrigger = nLeftTrigger;
m_cbSingleChange(curState, state);
}
// 右扳机
HitTriggerState(bPress, bRelease, bHolding, curState.bRightTrigger, lastState.bRightTrigger);
if (bPress || bRelease || bHolding)
{
GAMEPAD_INFO state = { 0 };
state.dwIndex = i;
state.bPress = bPress;
state.bRelease = bRelease;
state.bHolding = bHolding;
state.bRight = true;
state.bTrigger = nRightTrigger;
m_cbSingleChange(curState, state);
}
}
// 摇杆变化处理
{
// 左摇杆
if (curState.sThumbLX || curState.sThumbLY || m_bIgnoreLeftThumbEmpty)
{
GAMEPAD_INFO state = { 0 };
state.dwIndex = i;
state.sThumbX = curState.sThumbLX;
state.sThumbY = curState.sThumbLY;
state.bRight = false;
m_cbSingleChange(curState, state);
}
// 右摇杆
if (curState.sThumbRX || curState.sThumbRY || m_bIgnoreRightThumbEmpty)
{
GAMEPAD_INFO state = { 0 };
state.dwIndex = i;
state.sThumbX = curState.sThumbRX;
state.sThumbY = curState.sThumbRY;
state.bRight = true;
m_cbSingleChange(curState, state);
}
}
}
}
// 记录状态
xLastStateArray[i] = xCurStateArray[i];
}
// 多输入合并
{
// 限制范围
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;
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 (nLeftTrigger > UINT8_MAX) nLeftTrigger = UINT8_MAX;
if (nRightTrigger > UINT8_MAX) nRightTrigger = UINT8_MAX;
xCurStateMixed.Gamepad.sThumbLX = nThumbLX;
xCurStateMixed.Gamepad.sThumbLY = nThumbLY;
xCurStateMixed.Gamepad.sThumbRX = nThumbRX;
xCurStateMixed.Gamepad.sThumbRY = nThumbRY;
xCurStateMixed.Gamepad.bLeftTrigger = nLeftTrigger;
xCurStateMixed.Gamepad.bRightTrigger = nRightTrigger;
}
// 合并状态回调处理
if (m_cbMergeState)
{
m_cbMergeState(xCurStateMixed.Gamepad);
}
// 按键变化处理
for (const auto& item : buttonEvents)
{
bool bPress = false;
bool bRelease = false;
bool bHolding = false;
HitButtonState(bPress, bRelease, bHolding, xLastStateMixed.Gamepad, xCurStateMixed.Gamepad, item.first);
if (bPress || bRelease || bHolding)
{
GAMEPAD_INFO state = { 0 };
state.bPress = bPress;
state.bRelease = bRelease;
state.bHolding = bHolding;
state.wButton = item.first;
(this->*item.second)(xCurStateMixed.Gamepad, state);
// 合并数据变化回调
if (m_cbMergeChange)
{
m_cbMergeChange(xCurStateMixed.Gamepad, state);
}
}
}
// 扳机变化处理
{
bool bPress = false;
bool bRelease = false;
bool bHolding = false;
// 左扳机
HitTriggerState(bPress, bRelease, bHolding, nLeftTrigger, nLastLeftTrigger);
if (bPress || bRelease || bHolding)
{
GAMEPAD_INFO state = { 0 };
state.bPress = bPress;
state.bRelease = bRelease;
state.bHolding = bHolding;
state.bRight = false;
state.bTrigger = nLeftTrigger;
OnLeftTrigger(xCurStateMixed.Gamepad, state);
// 变化回调处理
if (m_cbMergeChange)
{
m_cbMergeChange(xCurStateMixed.Gamepad, state);
}
}
// 右扳机
HitTriggerState(bPress, bRelease, bHolding, nRightTrigger, nLastRightTrigger);
if (bPress || bRelease || bHolding)
{
GAMEPAD_INFO state = { 0 };
state.bPress = bPress;
state.bRelease = bRelease;
state.bHolding = bHolding;
state.bRight = true;
state.bTrigger = nRightTrigger;
OnRightTrigger(xCurStateMixed.Gamepad, state);
// 合并数据变化回调
if (m_cbMergeChange)
{
m_cbMergeChange(xCurStateMixed.Gamepad, state);
}
}
}
// 摇杆变化处理
{
// 左摇杆
if (xCurStateMixed.Gamepad.sThumbLX || xCurStateMixed.Gamepad.sThumbLY || m_bIgnoreLeftThumbEmpty)
{
GAMEPAD_INFO state = { 0 };
state.sThumbX = xCurStateMixed.Gamepad.sThumbLX;
state.sThumbY = xCurStateMixed.Gamepad.sThumbLY;
state.bRight = false;
OnLeftThumb(xCurStateMixed.Gamepad, state);
// 合并数据变化回调
if (m_cbMergeChange)
{
m_cbMergeChange(xCurStateMixed.Gamepad, state);
}
}
// 右摇杆
if (xCurStateMixed.Gamepad.sThumbRX || xCurStateMixed.Gamepad.sThumbRY || m_bIgnoreRightThumbEmpty)
{
GAMEPAD_INFO state = { 0 };
state.sThumbX = xCurStateMixed.Gamepad.sThumbRX;
state.sThumbY = xCurStateMixed.Gamepad.sThumbRY;
state.bRight = true;
OnRightThumb(xCurStateMixed.Gamepad, state);
// 合并数据变化回调
if (m_cbMergeChange)
{
m_cbMergeChange(xCurStateMixed.Gamepad, state);
}
}
}
// 记录上次状态
xLastStateMixed = xCurStateMixed;
nLastThumbLX= nThumbLX;
nLastThumbLY= nThumbLY;
nLastThumbRX= nThumbRX;
nLastThumbRY= nThumbRY;
nLastLeftTrigger = nLeftTrigger ;
nLastRightTrigger = nRightTrigger;
_Sleep(10);
}
}
bool CXInputHelper::OnButtonA(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state)
{
PrintState(state);
return true;
}
bool CXInputHelper::OnButtonB(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state)
{
PrintState(state);
return true;
}
bool CXInputHelper::OnButtonX(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state)
{
PrintState(state);
return true;
}
bool CXInputHelper::OnButtonY(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state)
{
PrintState(state);
return true;
}
bool CXInputHelper::OnButtonBack(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state)
{
PrintState(state);
return true;
}
bool CXInputHelper::OnButtonStart(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state)
{
PrintState(state);
return true;
}
bool CXInputHelper::OnButtonDpadUp(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state)
{
PrintState(state);
return true;
}
bool CXInputHelper::OnButtonDpadDown(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state)
{
PrintState(state);
return true;
}
bool CXInputHelper::OnButtonDpadLeft(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state)
{
PrintState(state);
return true;
}
bool CXInputHelper::OnButtonDpadRight(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state)
{
PrintState(state);
return true;
}
bool CXInputHelper::OnButtonLeftShoulder(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state)
{
PrintState(state);
return true;
}
bool CXInputHelper::OnButtonRightShoulder(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state)
{
PrintState(state);
return true;
}
bool CXInputHelper::OnButtonLeftThumb(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state)
{
PrintState(state);
return true;
}
bool CXInputHelper::OnButtonRightThumb(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state)
{
PrintState(state);
return true;
}
bool CXInputHelper::OnLeftTrigger(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state)
{
PrintState(state);
return true;
}
bool CXInputHelper::OnRightTrigger(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state)
{
PrintState(state);
return true;
}
bool CXInputHelper::OnLeftThumb(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state)
{
PrintState(state);
return true;
}
bool CXInputHelper::OnRightThumb(const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state)
{
PrintState(state);
return true;
}
void CXInputHelper::PrintState(const GAMEPAD_INFO& state)
{
return;
PrintText(_T("OnRightThumb Index: %d bRight: %d Trigger: %3d %6d,%6d Button: %04X Press: %d Release: %d Holding: %d\r\n"),
state.dwIndex, state.bRight, state.bTrigger, state.sThumbX, state.sThumbY, state.wButton, state.bPress, state.bRelease, state.bHolding);
}
测试:
main.cpp
// JoystickAssistant.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <string>
#include <iostream>
#include <windows.h>
#include <tchar.h>
#include "CXinputHelper.h"
#ifdef _UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endif
void LogPrintf(LPCTSTR pFormat, ...);
int main()
{
CXInputHelper obj;
obj.Initialize();
obj.IgnoreLeftThumbEmpty(false);
obj.IgnoreRightThumbEmpty(false);
obj.SetThumbThreshold(4096);
/*obj.SetSingleStateCallback([](DWORD dwIndex, const XINPUT_GAMEPAD& xGamepad)-> void {
LogPrintf(_T("Index: %2d wButtons: %04X LT: %3d, RT: %3d LS: %6d,%6d RS: %6d,%6d \r\n"),
dwIndex,
xGamepad.wButtons,
xGamepad.bLeftTrigger,
xGamepad.bRightTrigger,
xGamepad.sThumbLX, xGamepad.sThumbLY,
xGamepad.sThumbRX, xGamepad.sThumbRY
);
}
);*/
/*obj.SetMergeStateCallback([](const XINPUT_GAMEPAD& xGamepad)-> void {
LogPrintf(_T("%04X LT: %3d, RT: %3d LS: %6d,%6d RS: %6d,%6d \r\n"),
xGamepad.wButtons,
xGamepad.bLeftTrigger,
xGamepad.bRightTrigger,
xGamepad.sThumbLX, xGamepad.sThumbLY,
xGamepad.sThumbRX, xGamepad.sThumbRY
);
}
);*/
obj.SetSingleChangeCallback([](const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state)-> void {
LogPrintf(_T("Index: %d bRight: %d Trigger: %3d Thumb: %6d,%6d Button: %04X Press: %d Release: %d Holding: %d\r\n"),
state.dwIndex,
state.bRight, state.bTrigger, state.sThumbX, state.sThumbY, state.wButton, state.bPress, state.bRelease, state.bHolding);
}
);
/*obj.SetMergeChangeCallback([](const XINPUT_GAMEPAD& xGamepad, const GAMEPAD_INFO& state)-> void {
LogPrintf(_T("Index: %d bRight: %d Trigger: %3d %6d,%6d Button: %04X Press: %d Release: %d Holding: %d\r\n"),
state.dwIndex,
state.bRight, state.bTrigger, state.sThumbX, state.sThumbY, state.wButton, state.bPress, state.bRelease, state.bHolding);
}
);*/
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);
}