XInput手柄输入封装

59 篇文章 0 订阅
38 篇文章 0 订阅

功能全面地封装了XInput的输入,

1. 普通按钮按下, 按住, 弹起状态检查,

2. 摇杆4个方向的按下, 按住, 弹起检查

3. 按键状态变化检测并且记录按下触发时间, 按住保持时间, 方便用来完全自定义的输入功能

4. 多手柄输入合并

5. 支持检索 西瓜键(Guide按键)

CXInputHelper.h

#pragma once
//
// @brief: XInput 输入事件封装辅助类
// @copyright: Copyright 2024 FlameCyclone
// @license: MIT
// @birth: created by FlameCyclone on 2024-09-07
// @version: V1.0.0
// @revision: last revised by FlameCyclone on 2024-09-11
//

#include <windows.h>
#include <xinput.h>
#include <tchar.h>
#include <stdint.h>
#include <thread>
#include <functional>
#include <string>
#include <map>
#pragma comment(lib, "xinput.lib")

// 禁用无名结构体/联合体警告 Disable warning C4201:nameless struct/union
#if _MSC_VER >= 1200
#pragma warning(push)
#endif
#pragma warning(disable : 4201)

// 禁用警告: 未引用的形参
#pragma warning(disable : 4100)

#define PI                                  (3.141592653589793f)
#define ANGLE_RANGE                         (22.5f)

#ifdef _UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endif

//
// 游戏手柄按钮常量
//
//#define XINPUT_GAMEPAD_DPAD_UP                0x0001
//#define XINPUT_GAMEPAD_DPAD_DOWN              0x0002
//#define XINPUT_GAMEPAD_DPAD_LEFT              0x0004
//#define XINPUT_GAMEPAD_DPAD_RIGHT             0x0008
//#define XINPUT_GAMEPAD_START                  0x0010
//#define XINPUT_GAMEPAD_BACK                   0x0020
//#define XINPUT_GAMEPAD_LEFT_THUMB             0x0040
//#define XINPUT_GAMEPAD_RIGHT_THUMB            0x0080
//#define XINPUT_GAMEPAD_LEFT_SHOULDER          0x0100
//#define XINPUT_GAMEPAD_RIGHT_SHOULDER         0x0200
#define XINPUT_GAMEPAD_GUIDE                    (0x00000400)
#define XINPUT_GAMEPAD_SHARE                    (0x00000800)
//#define XINPUT_GAMEPAD_A                      0x1000
//#define XINPUT_GAMEPAD_B                      0x2000
//#define XINPUT_GAMEPAD_X                      0x4000
//#define XINPUT_GAMEPAD_Y                      0x8000
#define XINPUT_GAMEPAD_LEFT_TRIGGER             (0x00010000)
#define XINPUT_GAMEPAD_RIGHT_TRIGGER            (0x00020000)
#define XINPUT_GAMEPAD_LEFT_STICK               (0x00040000)
#define XINPUT_GAMEPAD_RIGHT_STICK              (0x00080000)

// 按键枚举
enum eGamepadButton
{
    eGamepad_None           = 0,            // 无
    eGamepad_Dpad_Up        = 1 << 0x00,    // 十字键 上 Up
    eGamepad_Dpad_Down      = 1 << 0x01,    // 十字键 下 Down
    eGamepad_Dpad_Left      = 1 << 0x02,    // 十字键 左 Left
    eGamepad_Dpad_Right     = 1 << 0x03,    // 十字键 右 Right
    eGamepad_Start          = 1 << 0x04,    // 菜单键(开始键) Start
    eGamepad_Back           = 1 << 0x05,    // 返回键(选择键) Back
    eGamepad_LSB            = 1 << 0x06,    // 左摇杆键 Left Stick Button
    eGamepad_RSB            = 1 << 0x07,    // 右摇杆键 Right Stick Button
    eGamepad_LB             = 1 << 0x08,    // 左肩键 Left Bumper
    eGamepad_RB             = 1 << 0x09,    // 右肩键 Right Bumper
    eGamepad_Guide          = 1 << 0x0A,    // 西瓜键(导航键) Guide
    eGamepad_Share          = 1 << 0x0B,    // 分享键(假设, 未验证) Share
    eGamepad_A              = 1 << 0x0C,    // A
    eGamepad_B              = 1 << 0x0D,    // B
    eGamepad_X              = 1 << 0x0E,    // X
    eGamepad_Y              = 1 << 0x0F,    // Y
    eGamepad_LT             = 1 << 0x10,    // 左扳机 Left Trigger
    eGamepad_RT             = 1 << 0x11,    // 右扳机 Right Trigger
    eGamepad_LS             = 1 << 0x12,    // 左摇杆 Left Stick
    eGamepad_RS             = 1 << 0x13,    // 右摇杆 Right Stick
};

// 按键状态位
typedef union _GAMEPAD_BUTTON_STATE
{
    uint32_t    Button;                     // 按钮状态值
    struct
    {
        // 标准 XBOX 控制器按钮
        uint16_t    Dpad_Up : 1;            // 十字键 上 Up
        uint16_t    Dpad_Down : 1;          // 十字键 下 Down
        uint16_t    Dpad_Left : 1;          // 十字键 左 Left
        uint16_t    Dpad_Right : 1;         // 十字键 右 Right
        uint16_t    Start : 1;              // 菜单键(开始键) Start
        uint16_t    Back : 1;               // 返回键(选择键) Back
        uint16_t    LSB : 1;                // 左摇杆键 Left Stick Button
        uint16_t    RSB : 1;                // 右摇杆键 Right Stick Button
        uint16_t    LB : 1;                 // 左肩键 Left Bumper
        uint16_t    RB : 1;                 // 右肩键 Right Bumper
        uint16_t    Guide : 1;              // 西瓜键(导航键) Guide
        uint16_t    Share : 1;              // 分享键(假设, 未验证) Share
        uint16_t    A : 1;                  // A
        uint16_t    B : 1;                  // B
        uint16_t    X : 1;                  // X
        uint16_t    Y : 1;                  // Y

        // 根据摇杆方向假设的摇杆方向键
        uint16_t    LS_Up : 1;              // 左摇杆 上
        uint16_t    LS_Down : 1;            // 左摇杆 下
        uint16_t    LS_Left : 1;            // 左摇杆 左
        uint16_t    LS_Right : 1;           // 左摇杆 右

        uint16_t    RS_Up : 1;              // 右摇杆 上
        uint16_t    RS_Down : 1;            // 右摇杆 下
        uint16_t    RS_Left : 1;            // 右摇杆 左
        uint16_t    RS_Right : 1;           // 右摇杆 右

        // 根据扳机假设的按键
        uint16_t    LT : 1;                 // 左扳机 Left Trigger
        uint16_t    RT : 1;                 // 右扳机 Right Trigger

        // 根据摇杆假设的按键
        uint16_t    LS : 1;                 // 左摇杆 Left Stick
        uint16_t    RS : 1;                 // 右摇杆 Right Stick

        uint16_t    Reserved : 4;           // 保留位
    } DUMMYSTRUCTNAME;

}GAMEPAD_BUTTON_STATE;

// 按钮事件
typedef struct _GAMEPAD_BUTTON_EVENT
{
    uint32_t uData;                         // 事件附加数据
    uint32_t uTime;                         // 触发时间
    uint32_t uDuration;                     // 持续时长

    union 
    {
        uint8_t    Event;                   // 事件值
        struct
        {
            uint8_t    Down : 1;            // 按下
            uint8_t    Hold : 1;            // 按住
            uint8_t    Up : 1;              // 弹起
        } DUMMYSTRUCTNAME;
    } DUMMYUNIONNAME;
}GAMEPAD_BUTTON_EVENT;

// 摇杆轴状态
typedef union _GAMEPAD_AXIS_STATE
{
    uint8_t    State;                       // 状态值
    struct
    {
        uint8_t    Up : 1;                  // 上
        uint8_t    Down : 1;                // 下
        uint8_t    Left : 1;                // 左
        uint8_t    Right : 1;               // 右
    } DUMMYSTRUCTNAME;
}GAMEPAD_AXIS_STATE;

// 摇杆轴事件
typedef struct _GAMEPAD_AXIS_EVENT
{
    GAMEPAD_BUTTON_EVENT Up;                // 轴方向事件上
    GAMEPAD_BUTTON_EVENT Down;              // 轴方向事件下
    GAMEPAD_BUTTON_EVENT Left;              // 轴方向事件左
    GAMEPAD_BUTTON_EVENT Right;             // 轴方向事件右

    GAMEPAD_AXIS_STATE curAxisState;        // 当前轴方向状态
    GAMEPAD_AXIS_STATE lastAxisState;       // 上次轴方向状态
}GAMEPAD_AXIS_EVENT;

// 输入事件状态
typedef struct _GAMEPAD_INPUT_EVENT
{
    uint32_t uIndex;                            // 手柄索引
    eGamepadButton eButton;                     // 当前按钮枚举
    XINPUT_STATE xinputState;                   // 当前手柄输入状态

    GAMEPAD_BUTTON_EVENT curButtonEvent;        // 当前按键事件
    GAMEPAD_AXIS_EVENT curAxisEvent;            // 当前轴事件

    GAMEPAD_BUTTON_STATE curButtonState;        // 当前按键位状态
    GAMEPAD_BUTTON_STATE lastButtonState;       // 上次按键位状态

    int16_t sAxisX;                             // 当前摇杆X值
    int16_t sAxisY;                             // 当前摇杆Y值
    uint8_t bTrigger;                           // 扳机数据
    uint8_t fRight;                             // 右 扳机/肩键/摇杆标志

    _GAMEPAD_INPUT_EVENT()
    {
        memset(this, 0, sizeof(*this));
    }

}GAMEPAD_INPUT_EVENT;

// 输入事件回调信息
class CXInputHelper;
typedef void (CXInputHelper::*pInputEventFn)(GAMEPAD_INPUT_EVENT& event);

typedef struct _INPUT_EVENT_INFO
{
    pInputEventFn cbEvent;                      // 输入事件变化回调函数
    GAMEPAD_INPUT_EVENT eventState;             // 输入事件变化状态

    _INPUT_EVENT_INFO(pInputEventFn cb)
        :
        cbEvent(cb)
    {

    }

}GAMEPAD_EVENT_CB_INFO;

class CXInputHelper
{
public:

    CXInputHelper();
    virtual ~CXInputHelper();

    // 打印文本
    static void PrintText(LPCTSTR pFormat, ...);

    // 初始化
    bool Initialize();

    // 反初始化
    void Uninitialize();

    // 打印状态信息
    virtual void PrintState(
        const GAMEPAD_INPUT_EVENT& event        // 按钮事件
    );

    // 设置数据轮询时间
    void SetInterval(
        int millisecond = 10                    // 数据轮询时间(毫秒)
    );

    // 设置轴触发阈值
    void SetAxisThreshold(
        int16_t nLeft = 4096,                   // 左摇杆触发阈值(死区)
        int16_t nRight = 4096                   // 右摇杆触发阈值(死区)
    );

    // 设置轴阈值请求回调
    void SetAxisThresholdQuery(
        std::function<void(
            int16_t& nLeft,                     // 左摇杆触发阈值(死区)
            int16_t& nRight                     // 右摇杆触发阈值(死区)
            )> cb
    );

    // 设置检测每个控制器输入数据回调
    void SetRawStateCallback(
        std::function<void(
            uint32_t dwIndex,                   // 控制器索引(有效值: 0 - 3)
            const XINPUT_GAMEPAD& xGamepad      // 控制器数据
            )> cb
    );

    // 设置合并多个控制器输入数据回调
    void SetMergeStateCallback(
        std::function<void(
            const XINPUT_GAMEPAD& xGamepad      // 控制器数据
            )> cb
    );

    // 设置检测每个控制器输入状态变化回调
    void SetRawEventCallback(
        std::function<void(
            GAMEPAD_INPUT_EVENT& event      // 回调事件信息
            )> cb
    );

    // 设置合并多个控制器输入状态变化回调
    void SetMergeEventCallback(
        std::function<void(
            GAMEPAD_INPUT_EVENT& event      // 回调事件信息
            )> cb
    );

    // 输入变化
    virtual void OnEventDpadUp(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnEventDpadDown(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnEventDpadLeft(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnEventDpadRight(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnEventBack(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnEventStart(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnEventGuide(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnEventShare(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnEventA(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnEventB(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnEventX(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnEventY(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnEventLB(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnEventRB(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnEventLT(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnEventRT(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnEventLS(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnEventRS(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnEventLSB(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnEventRSB(GAMEPAD_INPUT_EVENT& event) {};

    // 合并输入变化
    virtual void OnMergeEventDpadUp(GAMEPAD_INPUT_EVENT& event){};
    virtual void OnMergeEventDpadDown(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnMergeEventDpadLeft(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnMergeEventDpadRight(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnMergeEventBack(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnMergeEventStart(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnMergeEventGuide(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnMergeEventShare(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnMergeEventA(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnMergeEventB(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnMergeEventX(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnMergeEventY(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnMergeEventLB(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnMergeEventRB(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnMergeEventLT(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnMergeEventRT(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnMergeEventLS(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnMergeEventRS(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnMergeEventLSB(GAMEPAD_INPUT_EVENT& event) {};
    virtual void OnMergeEventRSB(GAMEPAD_INPUT_EVENT& event) {};

private:

    // 任务循环
    void _GamepadLoop();

    // 睡眠间隔
    void _Sleep(int millisecond);

    // 更新轴事件
    void _UpdateAxisEvent(GAMEPAD_BUTTON_EVENT& event, bool fCur, bool fLast);

    // 解析轴状态
    GAMEPAD_AXIS_STATE _ParseAxisState(int16_t sAxisX, int16_t sAxisY, int16_t nThreshold);

    // 更新按钮状态
    void _UpdateButtonState(GAMEPAD_INPUT_EVENT& event, const XINPUT_GAMEPAD& cur);

    // 更新按钮变化事件
    void _UpdateButtonEvent(GAMEPAD_INPUT_EVENT& event, const XINPUT_GAMEPAD& cur);

    // 状态变化输入处理
    void _InputEventProcess(uint32_t dwIndex);

    // 混合输入处理
    void _InputMergeProcess();

    // 混合输入变化处理
    void _InputMergeEventProcess();

private:

    std::function<void(uint32_t dwIndex, const XINPUT_GAMEPAD& xGamepad)>   m_cbRawState;       // 检测每个控制器输入数据回调
    std::function<void(const XINPUT_GAMEPAD& xGamepad)>                     m_cbMergeState;     // 合并多个控制器输入数据回调
    std::function<void(GAMEPAD_INPUT_EVENT& event)>                         m_cbRawEvent;       // 检测每个控制器输入事件回调
    std::function<void(GAMEPAD_INPUT_EVENT& event)>                         m_cbMergeEvent;     // 合并多个控制器输入事件回调
    std::function<void(int16_t& nLeft, int16_t& nRight)>                    m_cbAxisQuery;      // 摇杆轴阈值请求回调

    std::map<eGamepadButton, GAMEPAD_EVENT_CB_INFO>   m_buttonEvents[XUSER_MAX_COUNT];          // 按钮输入事件信息映射
    std::map<eGamepadButton, GAMEPAD_EVENT_CB_INFO>   m_mergeEvents;                            // 合并输入事件信息映射

    std::thread                         m_gamepadTask;                          // 控制器状态检测任务线程
    int32_t                             m_DataInterval;                         // 采集间隔时间
    int16_t                             m_LeftAxisThreshold;                    // 左摇杆触发阈值
    int16_t                             m_RightAxisThreshold;                   // 右摇杆触发阈值
    bool                                m_fQuit;                                // 退出标志

public:

    XINPUT_STATE                        m_CurXInputStateIndex[XUSER_MAX_COUNT];     // 当前控制器输入状态
    XINPUT_STATE                        m_CurXInputStateMerge;                      // 当前全部控制器混合输入状态
    GAMEPAD_BUTTON_STATE               m_CurButtonStateIndex[XUSER_MAX_COUNT];     // 当前按钮掩码状态
    GAMEPAD_BUTTON_STATE               m_CurButtonStateMerge;                      // 当前合并后按钮掩码状态
};

CXInputHelper.cpp

#include "CXInputHelper.h"
#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_fQuit(false),
    m_LeftAxisThreshold(0),
    m_RightAxisThreshold(0),
    m_DataInterval(10)
{
    memset(&m_CurXInputStateIndex, 0, sizeof(m_CurXInputStateIndex));
    memset(&m_CurXInputStateMerge, 0, sizeof(m_CurXInputStateMerge));
    memset(&m_CurButtonStateIndex, 0, sizeof(m_CurButtonStateIndex));
    memset(&m_CurButtonStateMerge, 0, sizeof(m_CurButtonStateMerge));

}

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::SetInterval(
    int millisecond
)
{
    m_DataInterval = millisecond;
}

void CXInputHelper::SetAxisThreshold(
    int16_t nLeft/* = 4096*/,
    int16_t nRight/* = 4096*/
)
{
    m_LeftAxisThreshold = nLeft;
    m_RightAxisThreshold = nRight;
}

void CXInputHelper::SetAxisThresholdQuery(
    std::function<void(
        int16_t& nLeft,
        int16_t& nRight
        )> cb
)
{
    m_cbAxisQuery = cb;
}

void CXInputHelper::SetRawStateCallback(
    std::function<void(
        uint32_t uIndex,
        const XINPUT_GAMEPAD& xGamepad
        )> cb
)
{
    m_cbRawState = cb;
}

void CXInputHelper::SetMergeStateCallback(
    std::function<void(
        const XINPUT_GAMEPAD& xGamepad
        )> cb
)
{
    m_cbMergeState = cb;
}

void CXInputHelper::SetRawEventCallback(
    std::function<void(
        GAMEPAD_INPUT_EVENT& event
        )> cb
)
{
    m_cbRawEvent = cb;
}

void CXInputHelper::SetMergeEventCallback(
    std::function<void(
        GAMEPAD_INPUT_EVENT& event
        )> cb
)
{
    m_cbMergeEvent = cb;
}

void CXInputHelper::PrintState(
    const GAMEPAD_INPUT_EVENT& event
)
{
    PrintText(_T("Mask: %08X bRight: %d Trigger: %3d Axis: %6d,%6d Data: %d Buttons: %.8X Duration: %6d L: %d U: %d R: %d D: %d\r\n"),
        event.eButton,
        event.fRight, event.bTrigger, 
        event.sAxisX, event.sAxisY,
        event.curButtonEvent.Event,
        event.curButtonState.Button,
        event.curButtonEvent.uDuration,
        event.curAxisEvent.Left.Event,
        event.curAxisEvent.Up.Event,
        event.curAxisEvent.Right.Event,
        event.curAxisEvent.Down.Event
    );
}

void CXInputHelper::_GamepadLoop()
{
    m_buttonEvents[0] = {
        {eGamepadButton::eGamepad_Dpad_Up       ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnEventDpadUp)             },
        {eGamepadButton::eGamepad_Dpad_Down     ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnEventDpadDown)           },
        {eGamepadButton::eGamepad_Dpad_Left     ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnEventDpadLeft)           },
        {eGamepadButton::eGamepad_Dpad_Right    ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnEventDpadRight)          },
        {eGamepadButton::eGamepad_Start         ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnEventStart)              },
        {eGamepadButton::eGamepad_Back          ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnEventBack)               },
        {eGamepadButton::eGamepad_LSB           ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnEventLSB)                },
        {eGamepadButton::eGamepad_RSB           ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnEventRSB)                },
        {eGamepadButton::eGamepad_LB            ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnEventLB)                 },
        {eGamepadButton::eGamepad_RB            ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnEventRB)                 },
        {eGamepadButton::eGamepad_Guide         ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnEventGuide)              },
        {eGamepadButton::eGamepad_Share         ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnEventShare)              },
        {eGamepadButton::eGamepad_A             ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnEventA)                  },
        {eGamepadButton::eGamepad_B             ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnEventB)                  },
        {eGamepadButton::eGamepad_X             ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnEventX)                  },
        {eGamepadButton::eGamepad_Y             ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnEventY)                  },
        {eGamepadButton::eGamepad_LT            ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnEventLT)                 },
        {eGamepadButton::eGamepad_RT            ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnEventRT)                 },
        {eGamepadButton::eGamepad_LS            ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnEventLS)                 },
        {eGamepadButton::eGamepad_RS            ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnEventRS)                 }
    };

    m_buttonEvents[1] = m_buttonEvents[0];
    m_buttonEvents[2] = m_buttonEvents[0];
    m_buttonEvents[3] = m_buttonEvents[0];

    m_mergeEvents = {
        {eGamepadButton::eGamepad_Dpad_Up       ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnMergeEventDpadUp)        },
        {eGamepadButton::eGamepad_Dpad_Down     ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnMergeEventDpadDown)      },
        {eGamepadButton::eGamepad_Dpad_Left     ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnMergeEventDpadLeft)      },
        {eGamepadButton::eGamepad_Dpad_Right    ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnMergeEventDpadRight)     },
        {eGamepadButton::eGamepad_Start         ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnMergeEventStart)         },
        {eGamepadButton::eGamepad_Back          ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnMergeEventBack)          },
        {eGamepadButton::eGamepad_LSB           ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnMergeEventLSB)           },
        {eGamepadButton::eGamepad_RSB           ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnMergeEventRSB)           },
        {eGamepadButton::eGamepad_LB            ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnMergeEventLB)            },
        {eGamepadButton::eGamepad_RB            ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnMergeEventRB)            },
        {eGamepadButton::eGamepad_Guide         ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnMergeEventGuide)         },
        {eGamepadButton::eGamepad_Share         ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnMergeEventShare)         },
        {eGamepadButton::eGamepad_A             ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnMergeEventA)             },
        {eGamepadButton::eGamepad_B             ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnMergeEventB)             },
        {eGamepadButton::eGamepad_X             ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnMergeEventX)             },
        {eGamepadButton::eGamepad_Y             ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnMergeEventY)             },
        {eGamepadButton::eGamepad_LT            ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnMergeEventLT)            },
        {eGamepadButton::eGamepad_RT            ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnMergeEventRT)            },
        {eGamepadButton::eGamepad_LS            ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnMergeEventLS)            },
        {eGamepadButton::eGamepad_RS            ,  GAMEPAD_EVENT_CB_INFO(&CXInputHelper::OnMergeEventRS)            }
    };

    // 加载 控制器状态检测 函数
    HMODULE hModule = LoadLibrary(_T("XInput1_4.dll"));
    if (NULL == hModule) hModule = LoadLibrary(_T("xinput1_3.dll"));
    if (NULL == hModule) return;
    typedef int(__stdcall* _XInputGetStateEx)(uint32_t dwUserIndex, XINPUT_STATE* pState);
    _XInputGetStateEx XInputGetStateEx = (_XInputGetStateEx)::GetProcAddress(hModule, (LPCSTR)100);
    if (nullptr == XInputGetStateEx)
    {
        XInputGetStateEx = (_XInputGetStateEx)::GetProcAddress(hModule, "XInputGetState");
    }

    int16_t nLeftAxisThreshold = m_LeftAxisThreshold;
    int16_t nRightAxisThreshold = m_RightAxisThreshold;

    clock_t tmCount = ::clock();
    while (!m_fQuit && XInputGetStateEx)
    {
        // 遍历控制器输入
        for (uint32_t i = 0; i < XUSER_MAX_COUNT; ++i)
        {
            XINPUT_STATE xTmpState = { 0 };
            uint32_t dwResult = XInputGetStateEx(i, &xTmpState);

            nLeftAxisThreshold = m_LeftAxisThreshold;
            nRightAxisThreshold = m_RightAxisThreshold;

            // 轴触发限定值查询
            if (m_cbAxisQuery)
            {
                m_cbAxisQuery(nLeftAxisThreshold, nRightAxisThreshold);
            }

            // 摇杆触发值限定
            if (abs(xTmpState.Gamepad.sThumbLX) < nLeftAxisThreshold) xTmpState.Gamepad.sThumbLX = 0;
            if (abs(xTmpState.Gamepad.sThumbLY) < nLeftAxisThreshold) xTmpState.Gamepad.sThumbLY = 0;
            if (abs(xTmpState.Gamepad.sThumbRX) < nRightAxisThreshold) xTmpState.Gamepad.sThumbRX = 0;
            if (abs(xTmpState.Gamepad.sThumbRY) < nRightAxisThreshold) xTmpState.Gamepad.sThumbRY = 0;

            m_CurXInputStateIndex[i] = xTmpState;

            // 原始数据回调
            if (m_cbRawState)
            {
                m_cbRawState(i, xTmpState.Gamepad);
            }

            // 未连接控制器
            if (ERROR_DEVICE_NOT_CONNECTED == dwResult)
            {
                continue;
            }

            // 单控制器输入变化处理
            _InputEventProcess(i);
        }

        // 混合输入处理
        _InputMergeProcess();

        // 混合输入变化处理
        _InputMergeEventProcess();

        // 输入轮询间隔
        while (clock() - tmCount < m_DataInterval)
        {
            _Sleep(1);
        }

        tmCount = clock();
    }

    if (hModule)
    {
        ::FreeLibrary(hModule);
    }
}

GAMEPAD_AXIS_STATE CXInputHelper::_ParseAxisState(int16_t sAxisX, int16_t sAxisY, int16_t nThreshold)
{
    GAMEPAD_AXIS_STATE axisResult = { 0 };
    double fCurAngle = atan2(sAxisY, sAxisX) * 180.0f / PI;
    if (fCurAngle < 0)
    {
        fCurAngle = 360.0f + fCurAngle;
    }

    // 上
    if (sAxisY > nThreshold)
    {
        if (fCurAngle >= (90.0f - ANGLE_RANGE) && fCurAngle <= (90.0f + ANGLE_RANGE))
        {
            axisResult.Up = 1;
        }
    }

    // 下
    if (sAxisY < -nThreshold)
    {
        if (fCurAngle >= (270.0f - ANGLE_RANGE) && fCurAngle <= (270.0f + ANGLE_RANGE))
        {
            axisResult.Down = 1;
        }
    }

    // 左
    if (sAxisX < -nThreshold)
    {
        if (fCurAngle >= (180.0f - ANGLE_RANGE) || fCurAngle <= (180.0f + ANGLE_RANGE))
        {
            axisResult.Left = 1;
        }
    }

    // 右
    if (sAxisX > nThreshold)
    {
        if (fCurAngle >= (360.0f - ANGLE_RANGE) || fCurAngle <= (0.0f + ANGLE_RANGE))
        {
            axisResult.Right = 1;
        }
    }

    // 左上
    if (sAxisX < -nThreshold && sAxisY > nThreshold)
    {
        if (fCurAngle > (90.0f + 45.0f - ANGLE_RANGE) && fCurAngle < (90.0f + 45.0f + ANGLE_RANGE))
        {
            axisResult.Left = 1;
            axisResult.Up = 1;
        }
    }

    // 右上
    if (sAxisX > nThreshold && sAxisY > nThreshold)
    {
        if (fCurAngle > (90.0f - 45.0f - ANGLE_RANGE) && fCurAngle < (90.0f - 45.0f + ANGLE_RANGE))
        {
            axisResult.Right = 1;
            axisResult.Up = 1;
        }
    }

    // 左下
    if (sAxisY < -nThreshold && sAxisX < -nThreshold)
    {
        if (fCurAngle > (270.0f - 45.0f - ANGLE_RANGE) && fCurAngle < (270.0f - 45.0f + ANGLE_RANGE))
        {
            axisResult.Left = 1;
            axisResult.Down = 1;
        }
    }

    // 右下
    if (sAxisY < -nThreshold && sAxisX > nThreshold)
    {
        if (fCurAngle > (270.0f + 45.0f - ANGLE_RANGE) && fCurAngle < (270.0f + 45.0f + ANGLE_RANGE))
        {
            axisResult.Right = 1;
            axisResult.Down = 1;
        }
    }

    return axisResult;
}

void CXInputHelper::_UpdateButtonState(GAMEPAD_INPUT_EVENT& event, const XINPUT_GAMEPAD& gamepad)
{
    eGamepadButton& eButton = event.eButton;
    event.curButtonState.Button = 0;

    // 左扳机
    if (eGamepadButton::eGamepad_LT & eButton)
    {
        if (gamepad.bLeftTrigger)
        {
            event.curButtonState.LT = 1;
        }
    }
    // 右扳机
    else if (eGamepadButton::eGamepad_RT & eButton)
    {
        if (gamepad.bRightTrigger)
        {
            event.curButtonState.RT = 1;
        }
    }
    // 左摇杆
    else if (eGamepadButton::eGamepad_LS & eButton)
    {
        GAMEPAD_AXIS_STATE axisState = _ParseAxisState(gamepad.sThumbLX, gamepad.sThumbLY, m_LeftAxisThreshold);
        event.curButtonState.LS_Up = axisState.Up;
        event.curButtonState.LS_Down = axisState.Down;
        event.curButtonState.LS_Left = axisState.Left;
        event.curButtonState.LS_Right = axisState.Right;

        if (axisState.State)
        {
            event.curButtonState.LS = 1;
        }
    }
    // 右摇杆
    else if (eGamepadButton::eGamepad_RS & eButton)
    {
        GAMEPAD_AXIS_STATE axisState = _ParseAxisState(gamepad.sThumbRX, gamepad.sThumbRY, m_RightAxisThreshold);
        event.curButtonState.RS_Up = axisState.Up;
        event.curButtonState.RS_Down = axisState.Down;
        event.curButtonState.RS_Left = axisState.Left;
        event.curButtonState.RS_Right = axisState.Right;

        if (axisState.State)
        {
            event.curButtonState.RS = 1;
        }
    }
    else
    {
        event.curButtonState.Button |= (eButton & gamepad.wButtons);
    }
}

void CXInputHelper::_UpdateAxisEvent(GAMEPAD_BUTTON_EVENT& event, bool fCur, bool fLast)
{
    clock_t curTime = ::clock();

    event.Down = false;
    event.Up = false;
    event.Hold = false;

    // 按下
    if (fCur && !fLast)
    {
        event.Down = true;
        event.uTime = curTime;
        event.uDuration = 0;
    }

    // 弹起
    if (!fCur && fLast)
    {
        event.Up = true;
        event.uDuration = curTime - event.uTime;
    }

    // 按住
    if (fCur && fLast)
    {
        event.Hold = true;
        event.uDuration = curTime - event.uTime;
    }

    // 无
    if (!fCur && !fLast)
    {
        event.uTime = 0;
        event.uDuration = 0;
    }
}

void CXInputHelper::_UpdateButtonEvent(GAMEPAD_INPUT_EVENT& event, const XINPUT_GAMEPAD& gamepad)
{
    eGamepadButton& eButton = event.eButton;
    clock_t curTime = ::clock();
    event.curButtonEvent.Event = 0;

    bool curDown = false;
    bool lastDown = false;

    // 左扳机
    if (eGamepadButton::eGamepad_LT & eButton)
    {
        curDown = event.curButtonState.LT;
        lastDown = event.lastButtonState.LT;
    }
    // 右扳机
    else if (eGamepadButton::eGamepad_RT & eButton)
    {
        curDown = event.curButtonState.RT;
        lastDown = event.lastButtonState.RT;
    }
    // 左摇杆
    else if (eGamepadButton::eGamepad_LS & eButton)
    {
        event.curAxisEvent.curAxisState = _ParseAxisState(gamepad.sThumbLX, gamepad.sThumbLY, m_LeftAxisThreshold);
        event.curButtonState.LS_Up = event.curAxisEvent.curAxisState.Up;
        event.curButtonState.LS_Down = event.curAxisEvent.curAxisState.Down;
        event.curButtonState.LS_Left = event.curAxisEvent.curAxisState.Left;
        event.curButtonState.LS_Right = event.curAxisEvent.curAxisState.Right;

        curDown = event.curAxisEvent.curAxisState.State;
        lastDown = event.curAxisEvent.lastAxisState.State;

        _UpdateAxisEvent(event.curAxisEvent.Up, event.curAxisEvent.curAxisState.Up, event.curAxisEvent.lastAxisState.Up);
        _UpdateAxisEvent(event.curAxisEvent.Down, event.curAxisEvent.curAxisState.Down, event.curAxisEvent.lastAxisState.Down);
        _UpdateAxisEvent(event.curAxisEvent.Left, event.curAxisEvent.curAxisState.Left, event.curAxisEvent.lastAxisState.Left);
        _UpdateAxisEvent(event.curAxisEvent.Right, event.curAxisEvent.curAxisState.Right, event.curAxisEvent.lastAxisState.Right);
    }
    // 右摇杆
    else if (eGamepadButton::eGamepad_RS & eButton)
    {
        event.curAxisEvent.curAxisState = _ParseAxisState(gamepad.sThumbRX, gamepad.sThumbRY, m_RightAxisThreshold);
        event.curButtonState.RS_Up = event.curAxisEvent.curAxisState.Up;
        event.curButtonState.RS_Down = event.curAxisEvent.curAxisState.Down;
        event.curButtonState.RS_Left = event.curAxisEvent.curAxisState.Left;
        event.curButtonState.RS_Right = event.curAxisEvent.curAxisState.Right;

        curDown = event.curAxisEvent.curAxisState.State;
        lastDown = event.curAxisEvent.lastAxisState.State;

        _UpdateAxisEvent(event.curAxisEvent.Up, event.curAxisEvent.curAxisState.Up, event.curAxisEvent.lastAxisState.Up);
        _UpdateAxisEvent(event.curAxisEvent.Down, event.curAxisEvent.curAxisState.Down, event.curAxisEvent.lastAxisState.Down);
        _UpdateAxisEvent(event.curAxisEvent.Left, event.curAxisEvent.curAxisState.Left, event.curAxisEvent.lastAxisState.Left);
        _UpdateAxisEvent(event.curAxisEvent.Right, event.curAxisEvent.curAxisState.Right, event.curAxisEvent.lastAxisState.Right);
    }
    else
    {
        curDown = event.curButtonState.Button & eButton;
        lastDown = event.lastButtonState.Button & eButton;
    }

    // 按下
    if (curDown && !lastDown)
    {
        event.curButtonEvent.Down = true;
        event.curButtonEvent.uTime = curTime;
        event.curButtonEvent.uDuration = 0;
    }

    // 按住
    if (curDown && lastDown)
    {
        event.curButtonEvent.Hold = true;
        event.curButtonEvent.uDuration = curTime - event.curButtonEvent.uTime;
    }

    // 弹起
    if (!curDown && lastDown)
    {
        event.curButtonEvent.Up = true;
        event.curButtonEvent.uDuration = curTime - event.curButtonEvent.uTime;
    }

    event.lastButtonState = event.curButtonState;
    event.curAxisEvent.lastAxisState = event.curAxisEvent.curAxisState;
}

void CXInputHelper::_InputEventProcess(uint32_t uIndex)
{
    // 状态处理 & 事件处理
    for (auto& item : m_buttonEvents[uIndex])
    {
        GAMEPAD_EVENT_CB_INFO& cbInfo = item.second;
        cbInfo.eventState.eButton = item.first;

        // 更新按钮状态
        _UpdateButtonState(cbInfo.eventState, m_CurXInputStateIndex[uIndex].Gamepad);

        // 更新按钮事件
        _UpdateButtonEvent(cbInfo.eventState, m_CurXInputStateIndex[uIndex].Gamepad);
    }

    // 得到全部输入状态
    m_CurButtonStateIndex[uIndex].Button = 0;
    for (auto& item : m_buttonEvents[uIndex])
    {
        GAMEPAD_EVENT_CB_INFO& cbInfo = item.second;
        if (eGamepadButton::eGamepad_LT & item.first)
        {
            m_CurButtonStateIndex[uIndex].LT = cbInfo.eventState.curButtonEvent.Down || cbInfo.eventState.curButtonEvent.Hold;
        }
        else if (eGamepadButton::eGamepad_RT & item.first)
        {
            m_CurButtonStateIndex[uIndex].RT = cbInfo.eventState.curButtonEvent.Down || cbInfo.eventState.curButtonEvent.Hold;
        }
        else if (eGamepadButton::eGamepad_LS & item.first)
        {
            m_CurButtonStateIndex[uIndex].LS = cbInfo.eventState.curButtonState.LS;
            m_CurButtonStateIndex[uIndex].LS_Up = cbInfo.eventState.curButtonState.LS_Up;
            m_CurButtonStateIndex[uIndex].LS_Down = cbInfo.eventState.curButtonState.LS_Down;
            m_CurButtonStateIndex[uIndex].LS_Left = cbInfo.eventState.curButtonState.LS_Left;
            m_CurButtonStateIndex[uIndex].LS_Right = cbInfo.eventState.curButtonState.LS_Right;
        }
        else if (eGamepadButton::eGamepad_RS & item.first)
        {
            m_CurButtonStateIndex[uIndex].RS = cbInfo.eventState.curButtonState.RS;
            m_CurButtonStateIndex[uIndex].RS_Up = cbInfo.eventState.curButtonState.RS_Up;
            m_CurButtonStateIndex[uIndex].RS_Down = cbInfo.eventState.curButtonState.RS_Down;
            m_CurButtonStateIndex[uIndex].RS_Left = cbInfo.eventState.curButtonState.RS_Left;
            m_CurButtonStateIndex[uIndex].RS_Right = cbInfo.eventState.curButtonState.RS_Right;
        }
        else
        {
            m_CurButtonStateIndex[uIndex].Button |= (cbInfo.eventState.curButtonEvent.Down || cbInfo.eventState.curButtonEvent.Hold) ? item.first : 0;
        }
    }

    // 回调处理
    for (auto& item : m_buttonEvents[uIndex])
    {
        GAMEPAD_EVENT_CB_INFO& cbInfo = item.second;
        cbInfo.eventState.uIndex = uIndex;

        cbInfo.eventState.curButtonState.Button = m_CurButtonStateIndex[uIndex].Button;

        if (cbInfo.eventState.curButtonEvent.Event)
        {
            cbInfo.eventState.xinputState = m_CurXInputStateIndex[uIndex];

            if (eGamepadButton::eGamepad_LT & item.first)
            {
                cbInfo.eventState.bTrigger = m_CurXInputStateIndex[uIndex].Gamepad.bLeftTrigger;
            }
            else if (eGamepadButton::eGamepad_RT & item.first)
            {
                cbInfo.eventState.fRight = true;
                cbInfo.eventState.bTrigger = m_CurXInputStateIndex[uIndex].Gamepad.bRightTrigger;
            }
            else if (eGamepadButton::eGamepad_LS & item.first)
            {
                cbInfo.eventState.sAxisX = m_CurXInputStateIndex[uIndex].Gamepad.sThumbLX;
                cbInfo.eventState.sAxisY = m_CurXInputStateIndex[uIndex].Gamepad.sThumbLY;
            }
            else if (eGamepadButton::eGamepad_RT & item.first)
            {
                cbInfo.eventState.fRight = true;
                cbInfo.eventState.sAxisX = m_CurXInputStateIndex[uIndex].Gamepad.sThumbRX;
                cbInfo.eventState.sAxisY = m_CurXInputStateIndex[uIndex].Gamepad.sThumbRY;
            }
            else if (eGamepadButton::eGamepad_RB & item.first)
            {
                cbInfo.eventState.fRight = true;
            }
            else if (eGamepadButton::eGamepad_RSB & item.first)
            {
                cbInfo.eventState.fRight = true;
            }

            (this->*(cbInfo.cbEvent))(cbInfo.eventState);

            if (m_cbRawEvent)
            {
                m_cbRawEvent(cbInfo.eventState);
            }
        }
    }
}

void CXInputHelper::_InputMergeProcess()
{
    int32_t nThumbLX = 0;
    int32_t nThumbLY = 0;
    int32_t nThumbRX = 0;
    int32_t nThumbRY = 0;
    uint32_t nLeftTrigger = 0;
    uint32_t nRightTrigger = 0;

    // 混合输入按钮状态
    m_CurXInputStateMerge.Gamepad.wButtons = 0;
    for (uint32_t i = 0; i < XUSER_MAX_COUNT; ++i)
    {
        m_CurXInputStateMerge.Gamepad.wButtons |= m_CurXInputStateIndex[i].Gamepad.wButtons;
        nThumbLX += m_CurXInputStateIndex[i].Gamepad.sThumbLX;
        nThumbLY += m_CurXInputStateIndex[i].Gamepad.sThumbLY;
        nThumbRX += m_CurXInputStateIndex[i].Gamepad.sThumbRX;
        nThumbRY += m_CurXInputStateIndex[i].Gamepad.sThumbRY;
        nLeftTrigger += m_CurXInputStateIndex[i].Gamepad.bLeftTrigger;
        nRightTrigger += m_CurXInputStateIndex[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_CurXInputStateMerge.Gamepad.bLeftTrigger = nLeftTrigger;
    m_CurXInputStateMerge.Gamepad.bRightTrigger = nRightTrigger;

    m_CurXInputStateMerge.Gamepad.sThumbLX = nThumbLX;
    m_CurXInputStateMerge.Gamepad.sThumbLY = nThumbLY;
    m_CurXInputStateMerge.Gamepad.sThumbRX = nThumbRX;
    m_CurXInputStateMerge.Gamepad.sThumbRY = nThumbRY;

    if (m_cbMergeState)
    {
        m_cbMergeState(m_CurXInputStateMerge.Gamepad);
    }
}

void CXInputHelper::_InputMergeEventProcess()
{
    // 状态处理 & 事件处理
    for (auto& item : m_mergeEvents)
    {
        GAMEPAD_EVENT_CB_INFO& cbInfo = item.second;
        cbInfo.eventState.eButton = item.first;

        // 更新按钮状态
        _UpdateButtonState(cbInfo.eventState, m_CurXInputStateMerge.Gamepad);

        // 更新按钮事件
        _UpdateButtonEvent(cbInfo.eventState, m_CurXInputStateMerge.Gamepad);
    }

    // 得到全部输入状态
    m_CurButtonStateMerge.Button = 0;
    for (auto& item : m_mergeEvents)
    {
        GAMEPAD_EVENT_CB_INFO& cbInfo = item.second;
        if (eGamepadButton::eGamepad_LT & item.first)
        {
            m_CurButtonStateMerge.LT = cbInfo.eventState.curButtonEvent.Down || cbInfo.eventState.curButtonEvent.Hold;
        }
        else if (eGamepadButton::eGamepad_RT & item.first)
        {
            m_CurButtonStateMerge.RT = cbInfo.eventState.curButtonEvent.Down || cbInfo.eventState.curButtonEvent.Hold;
        }
        else if (eGamepadButton::eGamepad_LS & item.first)
        {
            m_CurButtonStateMerge.LS = cbInfo.eventState.curButtonState.LS;
            m_CurButtonStateMerge.LS_Up = cbInfo.eventState.curButtonState.LS_Up;
            m_CurButtonStateMerge.LS_Down = cbInfo.eventState.curButtonState.LS_Down;
            m_CurButtonStateMerge.LS_Left = cbInfo.eventState.curButtonState.LS_Left;
            m_CurButtonStateMerge.LS_Right = cbInfo.eventState.curButtonState.LS_Right;

            cbInfo.eventState.sAxisX = m_CurXInputStateMerge.Gamepad.sThumbLX;
            cbInfo.eventState.sAxisY = m_CurXInputStateMerge.Gamepad.sThumbLY;
        }
        else if (eGamepadButton::eGamepad_RS & item.first)
        {
            m_CurButtonStateMerge.RS = cbInfo.eventState.curButtonState.RS;
            m_CurButtonStateMerge.RS_Up = cbInfo.eventState.curButtonState.RS_Up;
            m_CurButtonStateMerge.RS_Down = cbInfo.eventState.curButtonState.RS_Down;
            m_CurButtonStateMerge.RS_Left = cbInfo.eventState.curButtonState.RS_Left;
            m_CurButtonStateMerge.RS_Right = cbInfo.eventState.curButtonState.RS_Right;

            cbInfo.eventState.sAxisX = m_CurXInputStateMerge.Gamepad.sThumbRX;
            cbInfo.eventState.sAxisY = m_CurXInputStateMerge.Gamepad.sThumbRY;
        }
        else
        {
            m_CurButtonStateMerge.Button |= (cbInfo.eventState.curButtonEvent.Down || cbInfo.eventState.curButtonEvent.Hold) ? item.first : 0;
        }
    }

    // 回调处理
    for (auto& item : m_mergeEvents)
    {
        GAMEPAD_EVENT_CB_INFO& cbInfo = item.second;

        cbInfo.eventState.curButtonState.Button = m_CurButtonStateMerge.Button;

        if (cbInfo.eventState.curButtonEvent.Event)
        {
            cbInfo.eventState.xinputState = m_CurXInputStateMerge;

            if (eGamepadButton::eGamepad_LT & item.first)
            {
                cbInfo.eventState.bTrigger = m_CurXInputStateMerge.Gamepad.bLeftTrigger;
            }
            else if (eGamepadButton::eGamepad_RT & item.first)
            {
                cbInfo.eventState.fRight = true;
                cbInfo.eventState.bTrigger = m_CurXInputStateMerge.Gamepad.bRightTrigger;
            }
            else if (eGamepadButton::eGamepad_LS & item.first)
            {
                cbInfo.eventState.sAxisX = m_CurXInputStateMerge.Gamepad.sThumbLX;
                cbInfo.eventState.sAxisY = m_CurXInputStateMerge.Gamepad.sThumbLY;
            }
            else if (eGamepadButton::eGamepad_RS & item.first)
            {
                cbInfo.eventState.fRight = true;
                cbInfo.eventState.sAxisX = m_CurXInputStateMerge.Gamepad.sThumbRX;
                cbInfo.eventState.sAxisY = m_CurXInputStateMerge.Gamepad.sThumbRY;
            }
            else if (eGamepadButton::eGamepad_RB & item.first)
            {
                cbInfo.eventState.fRight = true;
            }
            else if (eGamepadButton::eGamepad_RSB & item.first)
            {
                cbInfo.eventState.fRight = true;
            }

            (this->*(cbInfo.cbEvent))(cbInfo.eventState);

            if (m_cbMergeEvent)
            {
                m_cbMergeEvent(cbInfo.eventState);
            }
        }
    }
}

main.cpp

#include <string>
#include <iostream>
#include <windows.h>
#include <tchar.h>
#include "CWin32Utils/CXinputHelper.h"
#include "CMainFrame.h"
#include "resource.h"

#ifdef _UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endif

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.SetAxisThreshold(4096, 4096);

#if 0
    obj.SetRawEventCallback([](const GAMEPAD_INPUT_EVENT& event)-> void {
        CXInputHelper::PrintText(_T("Mask: %08X bRight: %d Trigger: %3d Axis: %6d,%6d Data: %d Buttons: %.8X Duration: %6d Axis: (Left: %d Up: %d Right: %d Down: %d)\r\n"),
        event.eButton,
        event.fRight, event.bTrigger, 
        event.sAxisX, event.sAxisY,
        event.curButtonEvent.Event,
        event.curButtonState.Button,
        event.curButtonEvent.uDuration,
        event.curAxisEvent.Left.Event,
        event.curAxisEvent.Up.Event,
        event.curAxisEvent.Right.Event,
        event.curAxisEvent.Down.Event
        );

        }
    );
#endif

    obj.SetMergeEventCallback([](const GAMEPAD_INPUT_EVENT& event)-> void {
        CXInputHelper::PrintText(_T("Mask: %08X bRight: %d Trigger: %3d Axis: %6d,%6d Data: %d Buttons: %.8X Duration: %6d Axis: (Left: %d Up: %d Right: %d Down: %d)\r\n"),
        event.eButton,
        event.fRight, event.bTrigger, 
        event.sAxisX, event.sAxisY,
        event.curButtonEvent.Event,
        event.curButtonState.Button,
        event.curButtonEvent.uDuration,
        event.curAxisEvent.Left.Event,
        event.curAxisEvent.Up.Event,
        event.curAxisEvent.Right.Event,
        event.curAxisEvent.Down.Event
        );

        }
    );

    system("pause");

    return 0;
}

测试

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值