编写XBOX控制器实现鼠标键盘输入

1.核心部分, XINPUT输入封装

XInput封装https://mp.csdn.net/mp_blog/creation/editor/1420701282.对话框窗口编写

Win32 对话框封装-CSDN博客https://blog.csdn.net/Flame_Cyclone/article/details/142110008?spm=1001.2014.3001.5501

3.使用到的其他封装

字符串编码转换与常用操作(Win32,C++)_windows字符串编码转换-CSDN博客https://blog.csdn.net/Flame_Cyclone/article/details/135514476键盘鼠标模拟输入(Win32, C++)_win32 键盘输入-CSDN博客文章浏览阅读547次。简单封装SendInput的简单操作_win32 键盘输入https://blog.csdn.net/Flame_Cyclone/article/details/133162010Ini配置文件读写(Win32, C++)_win32 读取ini配置文件-CSDN博客文章浏览阅读134次。简单封装ini配置文件读写操作_win32 读取ini配置文件https://blog.csdn.net/Flame_Cyclone/article/details/130812165

4.结合输入与界面编写主要逻辑

main.cpp

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;
}

CMainFrame.h

cpp 复制代码
#pragma once
#include "CWindow/CDialogBase.h"
#include "CWin32Utils/CXInputHelper.h"
#include "CWin32Utils/CStrUtils.h"
#include "CWin32Utils/CIniHelper.h"

#define NORMAL_COLOR                                    RGB(200, 200, 255)
#define ACTIVE_COLOR                                    RGB(255, 255, 0)
#define LAST_BUTTON_COLOR                               RGB(128, 128, 255)
#define VALUE_COLOR                                     RGB(255, 255, 0)
#define LAST_VALUE_COLOR                                RGB(96, 96, 255)

#define MOUSE_MOVE_THRESHOLD                            (1024 * 6)     //鼠标移动摇杆阈值
#define MOUSE_SRCOLL_THRESHOLD                          (32768 / 2)     //鼠标滚轮摇杆阈值

enum eMouseType
{
    eMouseNone,
    eMouseMove,
    eMouseWheel,
    eMouseLeft,
    eMouseRight,
    eMouseMiddle
};


class CMainFrame: public CDialogBase, CXInputHelper
{
public:
    LRESULT OnInitDialog(WPARAM wParam, LPARAM lParam);
    LRESULT OnClose(WPARAM wParam, LPARAM lParam);
    LRESULT OnDestroy(WPARAM wParam, LPARAM lParam);
    LRESULT OnEraseBkgnd(WPARAM wParam, LPARAM lParam);
    LRESULT OnPaint(WPARAM wParam, LPARAM lParam);
    LRESULT OnLButtonDown(WPARAM wParam, LPARAM lParam);
    LRESULT OnDrawItem(WPARAM wParam, LPARAM lParam);
    LRESULT OnCtlColorDlg(WPARAM wParam, LPARAM lParam);

    LRESULT OnReset(WORD wNotify, WORD wID, HWND hWnd);
    LRESULT OnVibrationLeft(WORD wNotify, WORD wID, HWND hWnd);
    LRESULT OnVibrationRight(WORD wNotify, WORD wID, HWND hWnd);
    LRESULT OnKey(WORD wNotify, WORD wID, HWND hWnd);
    LRESULT OnMouse(WORD wNotify, WORD wID, HWND hWnd);
    LRESULT OnNone(WORD wNotify, WORD wID, HWND hWnd);

    LRESULT OnModifierChange(WORD wNotify, WORD wID, HWND hWnd);
    LRESULT OnKeyChange(WORD wNotify, WORD wID, HWND hWnd);
    LRESULT OnMouseChange(WORD wNotify, WORD wID, HWND hWnd);

    LRESULT OnDrawButton(WORD wNotify, WORD wID, HWND hWnd);

private:

    RECT GetItemRect(WORD wID);
    void DrawButtonItem(DWORD wID);
    void DrawStatic(LPDRAWITEMSTRUCT lpDrawItem, WORD wID);
    void DrawAxis(LPDRAWITEMSTRUCT lpDrawItem, WORD wID);
    void DrawNormalButton(LPDRAWITEMSTRUCT lpDrawItem, WORD wID);
    void DrawABXYButton(LPDRAWITEMSTRUCT lpDrawItem, WORD wID);
    void DrawDpadButton(LPDRAWITEMSTRUCT lpDrawItem, WORD wID);
    void DrawTriggerButton(LPDRAWITEMSTRUCT lpDrawItem, WORD wID);
    void UpdateButtonFunction(WORD wID);
    void ShowButtonFunction(WORD wID);

    void InitList();
    void SaveConfig();
    void LoadConfig();
    void DoFunction(WORD wID, GAMEPAD_INPUT_EVENT& event);
    void DoMouseMove(int x, int y);
    void DoMouseWheel(int x, int y);
private:

    // 方向键回调
    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 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 OnMergeEventLSB(GAMEPAD_INPUT_EVENT& event);
    virtual void OnMergeEventRSB(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);

protected:

    DECLARE_DLG_MESSAGE_MAP()

private:

    HDC             m_hMemDC = NULL;            // 内存DC
    HBITMAP         m_hMemBitmap = NULL;        // 内存位图
    HBRUSH          m_hBgBrush = NULL;

    XINPUT_STATE    m_lastState;
    bool m_fWndQuit = false;
    bool m_fVibrationLeft = false;
    bool m_fVibrationRight = false;
    HWND m_hModifier;
    HWND m_hKeys;
    HWND m_hMouse;
    HWND m_hNone;
    WORD m_wFocusID = 0;

    XINPUT_VIBRATION m_Vibration = { 0 };
    CIniHelper m_config;

    LONG m_sThumbLX_Min = 0;
    LONG m_sThumbLY_Min = 0;
    LONG m_sThumbRX_Min = 0;
    LONG m_sThumbRY_Min = 0;
    LONG m_sThumbLX_Max = 0;
    LONG m_sThumbLY_Max = 0;
    LONG m_sThumbRX_Max = 0;
    LONG m_sThumbRY_Max = 0;
};

CMainFrame.cpp

cpp 复制代码
#include "CMainFrame.h"
#include "resource.h"
#include <map>
#include <vector>
#include "CWin32Utils/CInputUtils.h"

enum eButtonFunction
{
    eNone,
    eKey,
    eMouse
};

typedef struct _BUTTON_FUNCTION_INFO
{
    eButtonFunction eType;                  // 0: 无 1: 键盘 2: 鼠标
    std::vector<int> vModifier;             // 修饰键名
    std::vector<int> vKeys;                 // 键盘名
    std::vector<int> vMouse;                // 鼠标功能
}BUTTON_FUNCTION_INFO;

std::map<DWORD, BUTTON_FUNCTION_INFO> g_ButtonFunctionList;

//原始按键
LPCTSTR g_ModifierName[] = {
    _T("None"),
    _T("LCtrl"),        
    _T("RCtrl"),        
    _T("LAlt"),         
    _T("RAlt"),         
    _T("LWin"),         
    _T("RWin"),         
    _T("LShift"),       
    _T("RShift")     
};

//原始按键
LPCTSTR g_KeysName[] = {
    _T("None"),
    _T("Esc"),          
    _T("F1"),           
    _T("F2"),           
    _T("F3"),           
    _T("F4"),           
    _T("F5"),           
    _T("F6"),           
    _T("F7"),           
    _T("F8"),           
    _T("F9"),           
    _T("F10"),          
    _T("F11"),          
    _T("F12"),          

    _T("`"),            
    _T("1"),            
    _T("2"),            
    _T("3"),            
    _T("4"),            
    _T("5"),            
    _T("6"),            
    _T("7"),            
    _T("8"),            
    _T("9"),            
    _T("0"),            
    _T("-"),            
    _T("="),            
    _T("Backspace"),    

    _T("Application"),  

    _T("Tab"),          
    _T("Space"),        
    _T("Enter"),        

    _T("["),            
    _T("]"),            
    _T("\\"),           

    _T(";"),            
    _T("\'"),           

    _T(","),            
    _T("."),            
    _T("/"),            

    _T("A"),            
    _T("B"),            
    _T("C"),            
    _T("D"),            
    _T("E"),            
    _T("F"),            
    _T("G"),            
    _T("H"),            
    _T("I"),            
    _T("J"),            
    _T("K"),            
    _T("L"),            
    _T("M"),            
    _T("N"),            
    _T("O"),            
    _T("P"),            
    _T("Q"),            
    _T("R"),            
    _T("S"),            
    _T("T"),            
    _T("U"),            
    _T("V"),            
    _T("W"),            
    _T("X"),            
    _T("Y"),            
    _T("Z"),            

    _T("Up"),           
    _T("Down"),         
    _T("Left"),         
    _T("Right"),        

    /*_T("UpArrow"),      
    _T("DownArrow"),    
    _T("LeftArrow"),    
    _T("RightArrow"),   */

    _T("Num Up"),       
    _T("Num Down"),     
    _T("Num Left"),     
    _T("Num Right"),    

    _T("Insert"),       
    _T("Home"),         
    _T("Page Up"),      
    _T("Delete"),       
    _T("End"),          
    _T("Page Down"),    

    _T("Prnt Scrn"),    
    _T("PrintScreen"),

    _T("Scroll Lock"),  
    _T("Num Lock"),     
    _T("Caps Lock"),    
    _T("Pause"),        

    _T("Num 0"),        
    _T("Num 1"),        
    _T("Num 2"),        
    _T("Num 3"),        
    _T("Num 4"),        
    _T("Num 5"),        
    _T("Num 6"),        
    _T("Num 7"),        
    _T("Num 8"),        
    _T("Num 9"),        

    _T("Num Home"),     
    _T("Num End"),      
    _T("Num Page Up"),  
    _T("Num Page Down"),

    _T("Clear"),        

    _T("Num /"),        
    _T("Num *"),        
    _T("Num -"),        
    _T("Num +"),        
    _T("Num Enter"),    
    _T("Num Del"),      
    _T("Num Insert"),   
    _T("Num ."),        

};  //118个按键

//原始按键
LPCTSTR g_MouseName[] = {
    _T("None"),
    _T("Move"),
    _T("Wheel"),
    _T("Left Button"),
    _T("Right Button"),
    _T("Middle Button"),
};

WORD g_DrawItemIDs[] = {
    IDC_BUTTON_LEFTSTICK        ,
    IDC_BUTTON_RIGHTSTICK       ,
    IDC_BUTTON_DPAD_UP          ,
    IDC_BUTTON_DPAD_DOWN        ,
    IDC_BUTTON_DPAD_LEFT        ,
    IDC_BUTTON_DPAD_RIGHT       ,
    IDC_BUTTON_Y                ,
    IDC_BUTTON_A                ,
    IDC_BUTTON_X                ,
    IDC_BUTTON_B                ,
    IDC_BUTTON_BACK             ,
    IDC_BUTTON_START            ,
    IDC_BUTTON_GUIDE            ,
    IDC_BUTTON_LB               ,
    IDC_BUTTON_RB               ,
    IDC_BUTTON_LT               ,
    IDC_BUTTON_RT               ,
    IDC_BUTTON_LSB               ,
    IDC_BUTTON_RSB               ,
    IDC_STATIC_LEFT_STICK_X    ,
    IDC_STATIC_LEFT_STICK_Y    ,
    IDC_STATIC_RIGHT_STICK_X   ,
    IDC_STATIC_RIGHT_STICK_Y   ,
};

BEGIN_DLG_MESSAGE_MAP(CMainFrame, CDialogBase)
    ON_DLG_MESSAGE(WM_INITDIALOG, &CMainFrame::OnInitDialog)
    ON_DLG_MESSAGE(WM_CLOSE, &CMainFrame::OnClose)
    ON_DLG_MESSAGE(WM_DESTROY, &CMainFrame::OnDestroy)
    ON_DLG_MESSAGE(WM_ERASEBKGND, &CMainFrame::OnEraseBkgnd)
    ON_DLG_MESSAGE(WM_PAINT, &CMainFrame::OnPaint)
    //ON_DLG_MESSAGE(WM_CTLCOLORDLG, &CMainFrame::OnCtlColorDlg)
    ON_DLG_MESSAGE(WM_LBUTTONDOWN, &CMainFrame::OnLButtonDown)
    ON_DLG_MESSAGE(WM_DRAWITEM, &CMainFrame::OnDrawItem)
    ON_DLG_COMMAND(IDC_CHECK_VIBRATION_LEFT, &CMainFrame::OnVibrationLeft)
    ON_DLG_COMMAND(IDC_CHECK_VIBRATION_RIGHT, &CMainFrame::OnVibrationRight)
    ON_DLG_COMMAND(IDC_BUTTON_RESET, &CMainFrame::OnReset)
    ON_DLG_COMMAND(IDC_RADIO_KEY, &CMainFrame::OnKey)
    ON_DLG_COMMAND(IDC_RADIO_MOUSE, &CMainFrame::OnMouse)
    ON_DLG_COMMAND(IDC_RADIO_NONE, &CMainFrame::OnNone)

    ON_DLG_COMMAND_NOTIFY(LBN_SELCHANGE, IDC_LIST_MODIFIER, &CMainFrame::OnKeyChange)
    ON_DLG_COMMAND_NOTIFY(LBN_SELCHANGE, IDC_LIST_KEYS, &CMainFrame::OnKeyChange)
    ON_DLG_COMMAND_NOTIFY(LBN_SELCHANGE, IDC_LIST_MOUSE, &CMainFrame::OnMouseChange)

    ON_DLG_COMMAND(IDC_BUTTON_LSB            , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_BUTTON_RSB            , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_BUTTON_LEFTSTICK     , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_BUTTON_RIGHTSTICK    , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_BUTTON_DPAD_UP       , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_BUTTON_DPAD_DOWN     , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_BUTTON_DPAD_LEFT     , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_BUTTON_DPAD_RIGHT    , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_BUTTON_Y             , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_BUTTON_A             , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_BUTTON_X             , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_BUTTON_B             , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_BUTTON_BACK          , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_BUTTON_START         , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_BUTTON_GUIDE         , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_BUTTON_LB            , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_BUTTON_RB            , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_BUTTON_LT            , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_BUTTON_RT            , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_BUTTON_RESET         , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_CHECK_VIBRATION_LEFT , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_CHECK_VIBRATION_RIGHT, &CMainFrame::OnDrawButton)

    ON_DLG_COMMAND(IDC_STATIC_LEFT_STICK_X  , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_STATIC_LEFT_STICK_Y  , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_STATIC_RIGHT_STICK_X , &CMainFrame::OnDrawButton)
    ON_DLG_COMMAND(IDC_STATIC_RIGHT_STICK_Y , &CMainFrame::OnDrawButton)

END_DLG_MESSAGE_MAP()

LRESULT CMainFrame::OnInitDialog(WPARAM wParam, LPARAM lParam)
{
    memset(&m_lastState, 0, sizeof(m_lastState));

    RECT rect = { 0 };
    ::GetClientRect(m_hWnd, &rect);
    WORD cxClient = rect.right - rect.left;
    WORD cyClient = rect.bottom - rect.top;

    HDC hdc = ::GetDC(m_hWnd);

    BuildDcBitmap(hdc, &m_hMemDC, &m_hMemBitmap, cxClient, cyClient);

    HFONT hFont = (HFONT)SendMessage(WM_GETFONT, 0, 0);
    m_hBgBrush = (HBRUSH)SendMessage(WM_CTLCOLORDLG, 0, 0);
    ::FillRect(m_hMemDC, &rect, m_hBgBrush);

    ::SelectObject(m_hMemDC, hFont);

    // 设置图标
    HICON hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON));
    if (hIcon)
    {
        ::SendMessage(m_hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
        ::SendMessage(m_hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
    }

    PostCommand(IDC_BUTTON_RESET);

    Initialize();

    m_hModifier = GetItem(IDC_LIST_MODIFIER);
    m_hKeys = GetItem(IDC_LIST_KEYS);
    m_hMouse = GetItem(IDC_LIST_MOUSE);
    InitList();

    ::EnableWindow(m_hModifier, FALSE);
    ::EnableWindow(m_hKeys, FALSE);
    ::EnableWindow(m_hMouse, FALSE);
    CheckButton(IDC_RADIO_NONE, true);
    CheckButton(IDC_RADIO_KEY, false);
    CheckButton(IDC_RADIO_MOUSE, false);

    LoadConfig();

    return (LRESULT)TRUE;
}

LRESULT CMainFrame::OnCtlColorDlg(WPARAM wParam, LPARAM lParam)
{
    return (LRESULT)GetStockBrush(WHITE_BRUSH);
}

LRESULT CMainFrame::OnClose(WPARAM wParam, LPARAM lParam)
{
    m_fWndQuit = true;
    Uninitialize();
    DeleteDcBitmap(&m_hMemDC, &m_hMemBitmap);

    SaveConfig();

    return (LRESULT)FALSE;
}

LRESULT CMainFrame::OnDestroy(WPARAM wParam, LPARAM lParam)
{
    return (LRESULT)FALSE;
}

LRESULT CMainFrame::OnEraseBkgnd(WPARAM wParam, LPARAM lParam)
{
    return (LRESULT)TRUE;
}

LRESULT CMainFrame::OnPaint(WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps = { 0 };
    HDC hdc = ::BeginPaint(m_hWnd, &ps);

    RECT rect = { 0 };
    ::GetClientRect(m_hWnd, &rect);

    {
        ::BitBlt(hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom, m_hMemDC, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
    }

    ::EndPaint(m_hWnd, &ps);

    return FALSE;
}

void CMainFrame::DrawButtonItem(DWORD wID)
{
    PostCommand(wID);
}

LRESULT CMainFrame::OnLButtonDown(WPARAM wParam, LPARAM lParam)
{
    for (const auto& item : g_DrawItemIDs)
    {
        RECT reReset = GetItemRect(item);
        POINT pt = { 0 };
        pt.x = GET_X_LPARAM(lParam);
        pt.y = GET_Y_LPARAM(lParam);

        if (PtInRect(&reReset, pt))
        {
            m_wFocusID = item;
        }
    }

    // 刷新显示
    for (auto item : g_DrawItemIDs)
    {
        DRAWITEMSTRUCT DrawItem = { 0 };
        DrawItem.CtlID = item;
        OnDrawItem(0, (LPARAM)&DrawItem);
        InvalidateRect(GetItem(item), NULL, FALSE);
    }

    ShowButtonFunction(m_wFocusID);

    return FALSE;
}

LRESULT CMainFrame::OnVibrationLeft(WORD wNotify, WORD wID, HWND hWnd)
{
    m_fVibrationLeft = IsButtonChecked(wID);

    return TRUE;
}

LRESULT CMainFrame::OnVibrationRight(WORD wNotify, WORD wID, HWND hWnd)
{
    m_fVibrationRight = IsButtonChecked(wID);

    return TRUE;
}

LRESULT CMainFrame::OnKey(WORD wNotify, WORD wID, HWND hWnd)
{
    EnableWindow(m_hModifier, true);
    EnableWindow(m_hKeys, true);
    EnableWindow(m_hMouse, false);

    UpdateButtonFunction(wID);
    return TRUE;
}

LRESULT CMainFrame::OnMouse(WORD wNotify, WORD wID, HWND hWnd)
{
    EnableWindow(m_hModifier, false);
    EnableWindow(m_hKeys, false);
    EnableWindow(m_hMouse, true);

    UpdateButtonFunction(wID);
    return TRUE;
}

LRESULT CMainFrame::OnNone(WORD wNotify, WORD wID, HWND hWnd)
{
    EnableWindow(m_hModifier, false);
    EnableWindow(m_hKeys, false);
    EnableWindow(m_hMouse, false);

    UpdateButtonFunction(wID);
    return TRUE;
}

LRESULT CMainFrame::OnReset(WORD wNotify, WORD wID, HWND hWnd)
{
    RECT rtClient = { 0 };

    ::GetClientRect(m_hWnd, &rtClient);

    ::FillRect(m_hMemDC, &rtClient, (HBRUSH)SendMessage(WM_CTLCOLORDLG, 0, 0));

    m_sThumbLX_Min = 0;
    m_sThumbLY_Min = 0;
    m_sThumbRX_Min = 0;
    m_sThumbRY_Min = 0;
    m_sThumbLX_Max = 0;
    m_sThumbLY_Max = 0;
    m_sThumbRX_Max = 0;
    m_sThumbRY_Max = 0;

    memset(&m_lastState, 0, sizeof(m_lastState));

    for (auto item : g_DrawItemIDs)
    {
        PostCommand(item);
    }

    return (LRESULT)TRUE;
}

LRESULT CMainFrame::OnDrawItem(WPARAM wParam, LPARAM lParam)
{
    LPDRAWITEMSTRUCT lpDrawItem = (LPDRAWITEMSTRUCT)lParam;
    lpDrawItem->hDC = m_hMemDC;
    lpDrawItem->rcItem = GetItemRect(lpDrawItem->CtlID);

    if (lpDrawItem->CtlID == IDC_BUTTON_A ||
        lpDrawItem->CtlID == IDC_BUTTON_B ||
        lpDrawItem->CtlID == IDC_BUTTON_X ||
        lpDrawItem->CtlID == IDC_BUTTON_Y
        )
    {
        DrawABXYButton(lpDrawItem, lpDrawItem->CtlID);
    }

    if (lpDrawItem->CtlID == IDC_BUTTON_DPAD_UP || 
        lpDrawItem->CtlID == IDC_BUTTON_DPAD_DOWN || 
        lpDrawItem->CtlID == IDC_BUTTON_DPAD_LEFT || 
        lpDrawItem->CtlID == IDC_BUTTON_DPAD_RIGHT
        )
    {
        DrawDpadButton(lpDrawItem, lpDrawItem->CtlID);
    }

    if (lpDrawItem->CtlID == IDC_BUTTON_LB ||
        lpDrawItem->CtlID == IDC_BUTTON_RB ||
        lpDrawItem->CtlID == IDC_BUTTON_LSB ||
        lpDrawItem->CtlID == IDC_BUTTON_RSB ||
        lpDrawItem->CtlID == IDC_BUTTON_BACK ||
        lpDrawItem->CtlID == IDC_BUTTON_GUIDE ||
        lpDrawItem->CtlID == IDC_BUTTON_START || 
        lpDrawItem->CtlID == IDC_BUTTON_RESET
        )
    {
        DrawNormalButton(lpDrawItem, lpDrawItem->CtlID);
    }

    if (lpDrawItem->CtlID == IDC_BUTTON_LT || 
        lpDrawItem->CtlID == IDC_BUTTON_RT
        )
    {
        DrawTriggerButton(lpDrawItem, lpDrawItem->CtlID);
    }

    if (lpDrawItem->CtlID == IDC_BUTTON_LEFTSTICK || 
        lpDrawItem->CtlID == IDC_BUTTON_RIGHTSTICK
        )
    {
        DrawAxis(lpDrawItem, lpDrawItem->CtlID);
    }

    if (lpDrawItem->CtlID == IDC_STATIC_LEFT_STICK_X ||
        lpDrawItem->CtlID == IDC_STATIC_LEFT_STICK_Y ||
        lpDrawItem->CtlID == IDC_STATIC_RIGHT_STICK_X ||
        lpDrawItem->CtlID == IDC_STATIC_RIGHT_STICK_Y
        )
    {
        DrawStatic(lpDrawItem, lpDrawItem->CtlID);
    }

    ::InvalidateRect(m_hWnd, &lpDrawItem->rcItem, FALSE);

    return (LRESULT)TRUE;
}

void CMainFrame::DrawStatic(LPDRAWITEMSTRUCT lpDrawItem, WORD wID)
{
    HBRUSH hBkgBrush = m_hBgBrush;

    HDC hdc = lpDrawItem->hDC;
    RECT rcItem = lpDrawItem->rcItem;

    LONG nWidth = rcItem.right - rcItem.left;
    LONG nHeight = rcItem.bottom - rcItem.top;

    LONG sThumbX = 0;
    LONG sThumbY = 0;

    if (wID == IDC_STATIC_LEFT_STICK_X)
    {
        sThumbX = m_CurXInputStateMerge.Gamepad.sThumbLX;
        _tstring strValue = CStrUtils::Format(_T("X: %6d"), sThumbX);
        RECT rtText = GetItemRect(IDC_STATIC_LEFT_STICK_X);
        ::FillRect(hdc, &rtText, hBkgBrush);
        ::TextOut(hdc, rtText.left, rtText.top, strValue.c_str(), strValue.size());
    }

    if (wID == IDC_STATIC_LEFT_STICK_X)
    {
        sThumbY = -m_CurXInputStateMerge.Gamepad.sThumbLY;
        _tstring strValue = CStrUtils::Format(_T("Y: %6d"), -sThumbY);
        RECT rtText = GetItemRect(IDC_STATIC_LEFT_STICK_Y);
        ::FillRect(hdc, &rtText, hBkgBrush);
        ::TextOut(hdc, rtText.left, rtText.top, strValue.c_str(), strValue.size());
    }

    if (wID == IDC_STATIC_RIGHT_STICK_X)
    {
        sThumbX = m_CurXInputStateMerge.Gamepad.sThumbRX;
        _tstring strValue = CStrUtils::Format(_T("X: %6d"), sThumbX);
        RECT rtText = GetItemRect(IDC_STATIC_RIGHT_STICK_X);
        ::FillRect(hdc, &rtText, hBkgBrush);
        ::TextOut(hdc, rtText.left, rtText.top, strValue.c_str(), strValue.size());
    }

    if (wID == IDC_STATIC_RIGHT_STICK_Y)
    {
        sThumbY = -m_CurXInputStateMerge.Gamepad.sThumbRY;
        _tstring strValue = CStrUtils::Format(_T("Y: %6d"), -sThumbY);
        RECT rtText = GetItemRect(IDC_STATIC_RIGHT_STICK_Y);
        ::FillRect(hdc, &rtText, hBkgBrush);
        ::TextOut(hdc, rtText.left, rtText.top, strValue.c_str(), strValue.size());
    }

}

RECT CMainFrame::GetItemRect(WORD wID)
{
    RECT rtItem = { 0 };
    ::GetWindowRect(GetItem(wID), &rtItem);

    POINT ptClient = { rtItem.left, rtItem.top };
    ::ScreenToClient(m_hWnd, &ptClient);

    RECT rtResult = { 0 };
    rtResult.left = ptClient.x;
    rtResult.top = ptClient.y;
    rtResult.right = ptClient.x + (rtItem.right - rtItem.left);
    rtResult.bottom = ptClient.y + (rtItem.bottom - rtItem.top);

    return rtResult;
}

void CMainFrame::DrawAxis(LPDRAWITEMSTRUCT lpDrawItem, WORD wID)
{
    HBRUSH hBkgBrush = m_hBgBrush;
    HBRUSH hNormalBrush = ::CreateSolidBrush(NORMAL_COLOR);
    HBRUSH hActiveBrush = ::CreateSolidBrush(ACTIVE_COLOR);
    HBRUSH hValueBrush = ::CreateSolidBrush(VALUE_COLOR);
    HBRUSH hLastBrush = ::CreateSolidBrush(LAST_BUTTON_COLOR);
    HBRUSH hLastValueBrush = ::CreateSolidBrush(LAST_VALUE_COLOR);

    HDC hdc = lpDrawItem->hDC;
    RECT rcItem = lpDrawItem->rcItem;

    LONG nWidth = rcItem.right - rcItem.left;
    LONG nHeight = rcItem.bottom - rcItem.top;

    LONG sThumbX = 0;
    LONG sThumbY = 0;

    _tstring strText = GetItemString(wID);

    ::SetBkMode(hdc, TRANSPARENT);
    {
        RECT rcBg = lpDrawItem->rcItem;
        rcBg.right += 1;
        rcBg.bottom += 1;
        ::FillRect(hdc, &rcBg, hBkgBrush);
    }

    HBRUSH hOldBrush = (HBRUSH)::SelectObject(hdc, hNormalBrush);
    ::Ellipse(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
    ::SelectObject(hdc, hOldBrush);

    if (wID == IDC_BUTTON_LEFTSTICK)
    {
        sThumbX = m_CurXInputStateMerge.Gamepad.sThumbLX;
        sThumbY = -m_CurXInputStateMerge.Gamepad.sThumbLY;
    }

    if (wID == IDC_BUTTON_RIGHTSTICK)
    {
        sThumbX = m_CurXInputStateMerge.Gamepad.sThumbRX;
        sThumbY = -m_CurXInputStateMerge.Gamepad.sThumbRY;
    }

    if (wID == IDC_BUTTON_LEFTSTICK)
    {
        RECT rtLast = {};
        rtLast.left = rcItem.left + nWidth / 2 + (double)m_sThumbLX_Min / (double)32768 * nWidth / 2;
        rtLast.top = rcItem.top + nHeight / 2 + (double)m_sThumbLY_Min / (double)32768 * nHeight / 2;
        rtLast.right = rcItem.left + nWidth / 2 + (double)m_sThumbLX_Max / (double)32768 * nWidth / 2 + 1;
        rtLast.bottom = rcItem.top + nWidth / 2 + (double)m_sThumbLY_Max / (double)32768 * nHeight / 2 + 1;

        ::FillRect(hdc, &rtLast, hLastValueBrush);
    }

    if (wID == IDC_BUTTON_RIGHTSTICK)
    {
        RECT rtLast = {};
        rtLast.left = rcItem.left + nWidth / 2 + (double)m_sThumbRX_Min / (double)32768 * nWidth / 2;
        rtLast.top = rcItem.top + nHeight / 2 + (double)m_sThumbRY_Min / (double)32768 * nHeight / 2;
        rtLast.right = rcItem.left + nWidth / 2 + (double)m_sThumbRX_Max / (double)32768 * nWidth / 2 + 1;
        rtLast.bottom = rcItem.top + nWidth / 2 + (double)m_sThumbRY_Max / (double)32768 * nHeight / 2 + 1;

        ::FillRect(hdc, &rtLast, hLastValueBrush);
    }

    {
        HBRUSH hOldBrush = (HBRUSH)::SelectObject(hdc, ::GetStockObject(NULL_BRUSH));
        HPEN hOldPen = (HPEN)::SelectObject(hdc, m_wFocusID == wID ? GetStockObject(BLACK_PEN) :  GetStockObject(WHITE_PEN));
        ::Ellipse(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
        ::SelectObject(hdc, hOldBrush);
        ::SelectObject(hdc, hOldPen);
    }

    {
        HPEN hOldPen = (HPEN)::SelectObject(hdc, GetStockObject(WHITE_PEN));
        ::MoveToEx(hdc, rcItem.left, rcItem.top + nHeight / 2, nullptr);
        ::LineTo(hdc, rcItem.right, rcItem.top + nHeight / 2);

        ::MoveToEx(hdc, rcItem.left + nWidth/ 2, rcItem.top, nullptr);
        ::LineTo(hdc, rcItem.left + nWidth/ 2, rcItem.bottom);
        ::SelectObject(hdc, hOldPen);
    }

    RECT rcThumb = rcItem;
    LONG nX = (double)sThumbX / (double)32768 * nWidth / 2;
    LONG nY = (double)sThumbY / (double)32768 * nHeight / 2;

    rcThumb.right = rcThumb.left + nX;
    rcThumb.bottom = rcThumb.top + nY;

    if (rcThumb.right < rcThumb.left)
    {
        LONG tmp = rcThumb.right;
        rcThumb.right = rcThumb.left;
        rcThumb.left = tmp;
    }

    if (rcThumb.bottom < rcThumb.top)
    {
        LONG tmp = rcThumb.bottom;
        rcThumb.bottom = rcThumb.top;
        rcThumb.top = tmp;
    }

    ::OffsetRect(&rcThumb, nWidth / 2, nHeight / 2);
    {
        HPEN hPen = CreatePen(PS_SOLID, 1, VALUE_COLOR);
        HPEN hOldPen = (HPEN)::SelectObject(hdc, hPen);
        HBRUSH hOldBrush = (HBRUSH)::SelectObject(hdc, hValueBrush);

        rcThumb.right += 1;
        rcThumb.bottom += 1;

        ::Rectangle(hdc, rcThumb.left, rcThumb.top, rcThumb.right, rcThumb.bottom);

        ::SelectObject(hdc, hOldBrush);
        ::SelectObject(hdc, hOldPen);
        ::DeleteObject(hPen);
    }

    ::DeleteObject(hLastBrush);
    ::DeleteObject(hValueBrush);
    ::DeleteObject(hLastValueBrush);
    ::DeleteObject(hNormalBrush);
    ::DeleteObject(hActiveBrush);
}

void CMainFrame::DrawTriggerButton(LPDRAWITEMSTRUCT lpDrawItem, WORD wID)
{
    HBRUSH hBkgBrush = m_hBgBrush;
    HBRUSH hNormalBrush = ::CreateSolidBrush(NORMAL_COLOR);
    HBRUSH hActiveBrush = ::CreateSolidBrush(ACTIVE_COLOR);
    HBRUSH hValueBrush = ::CreateSolidBrush(VALUE_COLOR);
    HBRUSH hLastBrush = ::CreateSolidBrush(LAST_BUTTON_COLOR);

    HDC hdc = lpDrawItem->hDC;
    RECT rcItem = lpDrawItem->rcItem;

    BYTE bTrigger = 0;
    BYTE bLastTrigger = 0;

    if (wID == IDC_BUTTON_LT)
    {
        bTrigger = m_CurXInputStateMerge.Gamepad.bLeftTrigger;
        bLastTrigger = m_lastState.Gamepad.bLeftTrigger;
    }

    if (wID == IDC_BUTTON_RT)
    {
        bTrigger = m_CurXInputStateMerge.Gamepad.bRightTrigger;
        bLastTrigger = m_lastState.Gamepad.bRightTrigger;
    }

    _tstring strText = GetItemString(wID);

    ::SetBkMode(hdc, TRANSPARENT);
    ::FillRect(hdc, &rcItem, hNormalBrush);

    {
        RECT rcTrigger = rcItem;
        rcTrigger.top = rcItem.bottom - ((rcItem.bottom - rcItem.top) * (double)((double)bLastTrigger / (double)255));
        ::FillRect(hdc, &rcTrigger, hLastBrush);
    }

    {
        RECT rcTrigger = rcItem;
        rcTrigger.top = rcItem.bottom - ((rcItem.bottom - rcItem.top) * (double)((double)bTrigger / (double)255));
        ::FillRect(hdc, &rcTrigger, hActiveBrush);
    }

    ::FrameRect(hdc, &rcItem, hBkgBrush);
    ::DrawText(hdc, strText.c_str(), strText.size(), &rcItem, DT_CENTER | DT_VCENTER | DT_SINGLELINE);

    _tstring strValue = CStrUtils::Format(_T("%d"), bTrigger);
    rcItem.bottom -= 4;
    ::DrawText(hdc, strValue.c_str(), strValue.size(), &rcItem, DT_CENTER | DT_BOTTOM | DT_SINGLELINE);

    {
        rcItem = lpDrawItem->rcItem;
        ::FrameRect(hdc, &rcItem, wID == m_wFocusID ? GetStockBrush(BLACK_BRUSH) : GetStockBrush(WHITE_BRUSH));
    }

    ::DeleteObject(hLastBrush);
    ::DeleteObject(hValueBrush);
    ::DeleteObject(hNormalBrush);
    ::DeleteObject(hActiveBrush);
}

void CMainFrame::DrawABXYButton(LPDRAWITEMSTRUCT lpDrawItem, WORD wID)
{
    HBRUSH hNormalBrush = ::CreateSolidBrush(NORMAL_COLOR);
    HBRUSH hActiveBrush = ::CreateSolidBrush(ACTIVE_COLOR);
    HBRUSH hValueBrush = ::CreateSolidBrush(VALUE_COLOR);
    HBRUSH hLastBrush = ::CreateSolidBrush(LAST_BUTTON_COLOR);


    HDC hdc = lpDrawItem->hDC;
    RECT rcItem = lpDrawItem->rcItem;

    bool fHitState = 0;
    bool fLastState = 0;
    DWORD dwTextColor = RGB(0, 0, 0);

    if (wID == IDC_BUTTON_X)
    {
        fHitState = m_CurXInputStateMerge.Gamepad.wButtons & XINPUT_GAMEPAD_X;
        fLastState = m_lastState.Gamepad.wButtons & XINPUT_GAMEPAD_X;
        dwTextColor = RGB(0, 51, 103);
    }

    if (wID == IDC_BUTTON_Y)
    {
        fHitState = m_CurXInputStateMerge.Gamepad.wButtons & XINPUT_GAMEPAD_Y;
        fLastState = m_lastState.Gamepad.wButtons & XINPUT_GAMEPAD_Y;
        dwTextColor = RGB(255, 255, 0);
    }

    if (wID == IDC_BUTTON_B)
    {
        fHitState = m_CurXInputStateMerge.Gamepad.wButtons & XINPUT_GAMEPAD_B;
        fLastState = m_lastState.Gamepad.wButtons & XINPUT_GAMEPAD_B;
        dwTextColor = RGB(255, 0, 0);
    }

    if (wID == IDC_BUTTON_A)
    {
        fHitState = m_CurXInputStateMerge.Gamepad.wButtons & XINPUT_GAMEPAD_A;
        fLastState = m_lastState.Gamepad.wButtons & XINPUT_GAMEPAD_A;
        dwTextColor = RGB(0, 255, 0);
    }

    _tstring strText = GetItemString(wID);

    ::SetBkMode(hdc, TRANSPARENT);

    HPEN hOldPen = (HPEN)::SelectObject(hdc, wID == m_wFocusID ? GetStockObject(BLACK_PEN) : GetStockObject(WHITE_PEN));

    // 焦点状态
    if (fHitState)
    {
        // 绘制按键
        HBRUSH hOldBrush = (HBRUSH)::SelectObject(hdc, hActiveBrush);
        ::Ellipse(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
        ::SelectObject(hdc, hOldBrush);
    }
    else
    {
        if (fLastState)
        {
            HBRUSH hOldBrush = (HBRUSH)::SelectObject(hdc, hLastBrush);
            ::Ellipse(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
            ::SelectObject(hdc, hOldBrush);
        }
        else
        {
            HBRUSH hOldBrush = (HBRUSH)::SelectObject(hdc, hNormalBrush);
            ::Ellipse(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
            ::SelectObject(hdc, hOldBrush);
        }
    }
    ::SelectObject(hdc, hOldPen);

    // 绘制文本
    DWORD dwLastColor = ::SetTextColor(hdc, dwTextColor);
    ::DrawText(hdc, strText.c_str(), strText.size(), &rcItem, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
    ::SetTextColor(hdc, dwLastColor);

    ::DeleteObject(hLastBrush);
    ::DeleteObject(hValueBrush);
    ::DeleteObject(hNormalBrush);
    ::DeleteObject(hActiveBrush);
}

void CMainFrame::DrawDpadButton(LPDRAWITEMSTRUCT lpDrawItem, WORD wID)
{
    HBRUSH hBkgBrush = m_hBgBrush;
    HBRUSH hNormalBrush = ::CreateSolidBrush(NORMAL_COLOR);
    HBRUSH hActiveBrush = ::CreateSolidBrush(ACTIVE_COLOR);
    HBRUSH hValueBrush = ::CreateSolidBrush(VALUE_COLOR);
    HBRUSH hLastBrush = ::CreateSolidBrush(LAST_BUTTON_COLOR);


    HDC hdc = lpDrawItem->hDC;
    RECT rcItem = lpDrawItem->rcItem;
    LONG nWidth = rcItem.right - rcItem.left;
    LONG nHeight = rcItem.bottom - rcItem.top;


    POINT ptButton[3] = { 0 };
    bool fHitState = 0;
    bool fLastState = 0;

    if (wID == IDC_BUTTON_DPAD_UP)
    {
        fHitState = m_CurXInputStateMerge.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP;
        fLastState = m_lastState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP;

        ptButton[0] = {rcItem.left + nWidth / 4, rcItem.bottom - nHeight / 4};
        ptButton[1] = {rcItem.right - nWidth / 4, rcItem.bottom - nHeight / 4};
        ptButton[2] = {rcItem.left + nWidth / 2, rcItem.top + nHeight / 3};
    }

    if (wID == IDC_BUTTON_DPAD_DOWN)
    { 
        fHitState = m_CurXInputStateMerge.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN;
        fLastState = m_lastState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN;

        ptButton[0] = {rcItem.left + nWidth / 4, rcItem.top + nHeight / 4};
        ptButton[1] = {rcItem.right - nWidth / 4, rcItem.top + nHeight / 4};
        ptButton[2] = {rcItem.left + nWidth / 2, rcItem.bottom - nHeight / 3};
    }

    if (wID == IDC_BUTTON_DPAD_LEFT)
    { 
        fHitState = m_CurXInputStateMerge.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT;
        fLastState = m_lastState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT;

        ptButton[0] = {rcItem.right - nWidth / 4, rcItem.top + nHeight / 4};
        ptButton[1] = {rcItem.right - nWidth / 4, rcItem.bottom - nHeight / 4};
        ptButton[2] = {rcItem.left + nWidth / 3, rcItem.top + nHeight / 2};
    }

    if (wID == IDC_BUTTON_DPAD_RIGHT)
    { 
        fHitState = m_CurXInputStateMerge.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT;
        fLastState = m_lastState.Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT;

        ptButton[0] = {rcItem.left + nWidth / 4, rcItem.top + nHeight / 4};
        ptButton[1] = {rcItem.left + nWidth / 4, rcItem.bottom - nHeight / 4};
        ptButton[2] = {rcItem.right - nWidth / 3, rcItem.top + nHeight / 2};
    }

    _tstring strText = GetItemString(wID);

    ::SetBkMode(hdc, TRANSPARENT);

    // 焦点状态
    if (fHitState)
    {
        ::FillRect(hdc, &rcItem, hActiveBrush);
        ::FrameRect(hdc, &rcItem, hBkgBrush);
    }
    else
    {
        if (fLastState)
        {
            ::FillRect(hdc, &rcItem, hLastBrush);
            ::FrameRect(hdc, &rcItem, hBkgBrush);
        }
        else
        {
            ::FillRect(hdc, &rcItem, hNormalBrush);
            ::FrameRect(hdc, &rcItem, hBkgBrush);
        }
    }

    {
        // 绘制按键
        HPEN hPen = CreatePen(PS_NULL, 1, VALUE_COLOR);
        HPEN hOldPen = (HPEN)::SelectObject(hdc, hPen);
        ::Polygon(hdc, ptButton, _countof(ptButton));
        ::SelectObject(hdc, hOldPen);
        ::DeleteObject(hPen);
    }

    ::FrameRect(hdc, &rcItem, wID == m_wFocusID ? GetStockBrush(BLACK_BRUSH) : GetStockBrush(WHITE_BRUSH));

    ::DeleteObject(hLastBrush);
    ::DeleteObject(hValueBrush);
    ::DeleteObject(hNormalBrush);
    ::DeleteObject(hActiveBrush);
}

void CMainFrame::DrawNormalButton(LPDRAWITEMSTRUCT lpDrawItem, WORD wID)
{
    HBRUSH hBkgBrush = m_hBgBrush;
    HBRUSH hNormalBrush = ::CreateSolidBrush(NORMAL_COLOR);
    HBRUSH hActiveBrush = ::CreateSolidBrush(ACTIVE_COLOR);
    HBRUSH hValueBrush = ::CreateSolidBrush(VALUE_COLOR);
    HBRUSH hLastBrush = ::CreateSolidBrush(LAST_BUTTON_COLOR);


    HDC hdc = lpDrawItem->hDC;
    RECT rcItem = lpDrawItem->rcItem;
    LONG nWidth = rcItem.right - rcItem.left;
    LONG nHeight = rcItem.bottom - rcItem.top;

    bool fHitState = 0;
    bool fLastState = 0;

    if (wID == IDC_BUTTON_LSB)      fHitState = m_CurButtonStateMerge.LSB;
    if (wID == IDC_BUTTON_RSB)      fHitState = m_CurButtonStateMerge.RSB;
    if (wID == IDC_BUTTON_X)        fHitState = m_CurButtonStateMerge.X;
    if (wID == IDC_BUTTON_Y)        fHitState = m_CurButtonStateMerge.Y;
    if (wID == IDC_BUTTON_B)        fHitState = m_CurButtonStateMerge.B;
    if (wID == IDC_BUTTON_A)        fHitState = m_CurButtonStateMerge.A;
    if (wID == IDC_BUTTON_LB)       fHitState = m_CurButtonStateMerge.LB;
    if (wID == IDC_BUTTON_RB)       fHitState = m_CurButtonStateMerge.RB;
    if (wID == IDC_BUTTON_BACK)     fHitState = m_CurButtonStateMerge.Back;
    if (wID == IDC_BUTTON_GUIDE)    fHitState = m_CurButtonStateMerge.Guide;
    if (wID == IDC_BUTTON_START)    fHitState = m_CurButtonStateMerge.Start;

    if (wID == IDC_BUTTON_LSB)      fLastState = m_lastState.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB;
    if (wID == IDC_BUTTON_RSB)      fLastState = m_lastState.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB;
    if (wID == IDC_BUTTON_X)        fLastState = m_lastState.Gamepad.wButtons & XINPUT_GAMEPAD_X;
    if (wID == IDC_BUTTON_Y)        fLastState = m_lastState.Gamepad.wButtons & XINPUT_GAMEPAD_Y;
    if (wID == IDC_BUTTON_B)        fLastState = m_lastState.Gamepad.wButtons & XINPUT_GAMEPAD_B;
    if (wID == IDC_BUTTON_A)        fLastState = m_lastState.Gamepad.wButtons & XINPUT_GAMEPAD_A;
    if (wID == IDC_BUTTON_LB)       fLastState = m_lastState.Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER;
    if (wID == IDC_BUTTON_RB)       fLastState = m_lastState.Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER;
    if (wID == IDC_BUTTON_BACK)     fLastState = m_lastState.Gamepad.wButtons & XINPUT_GAMEPAD_BACK;
    if (wID == IDC_BUTTON_GUIDE)    fLastState = m_lastState.Gamepad.wButtons & XINPUT_GAMEPAD_GUIDE;
    if (wID == IDC_BUTTON_START)    fLastState = m_lastState.Gamepad.wButtons & XINPUT_GAMEPAD_START;

    _tstring strText = GetItemString(wID);

    ::SetBkMode(hdc, TRANSPARENT);

    HBRUSH hFillBrush = hActiveBrush;
    // 焦点状态
    if (fHitState)
    {
        hFillBrush = hActiveBrush;
    }
    else
    {
        if (fLastState)
        {
            hFillBrush = hLastBrush;
        }
        else
        {
            hFillBrush = hNormalBrush;
        }
    }

    // 焦点状态
    if (IDC_BUTTON_GUIDE != wID)
    {
        ::FillRect(hdc, &rcItem, hFillBrush);
        ::FrameRect(hdc, &rcItem, hBkgBrush);
    }

    if (IDC_BUTTON_GUIDE == wID)
    {
        // 绘制背景
        HBRUSH hOldBrush = (HBRUSH)::SelectObject(hdc, hFillBrush);

        HPEN hOldPen = (HPEN)::SelectObject(hdc, wID == m_wFocusID ? GetStockObject(BLACK_PEN) : GetStockObject(WHITE_PEN));
        ::Ellipse(hdc, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
        ::SelectObject(hdc, hOldPen);

        ::SelectObject(hdc, hOldBrush);
        ::DrawText(hdc, strText.c_str(), strText.size(), &rcItem, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
    }
    else if (IDC_BUTTON_BACK == wID)
    {
        RECT rtButton = rcItem;
        rtButton.top = rcItem.top + nHeight / 8;
        rtButton.bottom = rtButton.top + nHeight / 2;
        rtButton.left = rcItem.left + nWidth / 8;
        rtButton.right = rcItem.right - nWidth / 3;
        ::FillRect(hdc, &rtButton, GetStockBrush(WHITE_BRUSH));

        ::InflateRect(&rtButton, -4, -4);
        ::FillRect(hdc, &rtButton, hFillBrush);

        rtButton = rcItem;
        rtButton.top = rcItem.top + nHeight / 8;
        rtButton.bottom = rtButton.top + nHeight / 2;
        rtButton.left = rcItem.left + nWidth / 8;
        rtButton.right = rcItem.right - nWidth / 3;

        ::OffsetRect(&rtButton, nWidth / 8, nHeight / 8);
        ::FillRect(hdc, &rtButton, hFillBrush);

        ::OffsetRect(&rtButton, nWidth / 8, nHeight / 8);

        ::FillRect(hdc, &rtButton, GetStockBrush(WHITE_BRUSH));
        ::InflateRect(&rtButton, -4, -4);
        ::FillRect(hdc, &rtButton, hFillBrush);

        ::FrameRect(hdc, &rcItem, wID == m_wFocusID ? GetStockBrush(BLACK_BRUSH) : GetStockBrush(WHITE_BRUSH));
    }
    else if (IDC_BUTTON_START == wID)
    {
        RECT rtButton = rcItem;
        rtButton.top = rcItem.top + nHeight / 6;
        rtButton.bottom = rtButton.top + nHeight / 8;
        rtButton.left = rcItem.left + nWidth / 8;
        rtButton.right = rcItem.right - nWidth / 8;
        ::FillRect(hdc, &rtButton, GetStockBrush(WHITE_BRUSH));

        ::OffsetRect(&rtButton, 0, nHeight / 4);
        ::FillRect(hdc, &rtButton, GetStockBrush(WHITE_BRUSH));

        ::OffsetRect(&rtButton, 0, nHeight / 4);
        ::FillRect(hdc, &rtButton, GetStockBrush(WHITE_BRUSH));

        ::FrameRect(hdc, &rcItem, wID == m_wFocusID ? GetStockBrush(BLACK_BRUSH) : GetStockBrush(WHITE_BRUSH));
    }
    else
    {
        ::FrameRect(hdc, &rcItem, wID == m_wFocusID ? GetStockBrush(BLACK_BRUSH) : GetStockBrush(WHITE_BRUSH));

        ::DrawText(hdc, strText.c_str(), strText.size(), &rcItem, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
    }

    ::DeleteObject(hLastBrush);
    ::DeleteObject(hValueBrush);
    ::DeleteObject(hNormalBrush);
    ::DeleteObject(hActiveBrush);
}

LRESULT CMainFrame::OnDrawButton(WORD wNotify, WORD wID, HWND hWnd)
{
    DRAWITEMSTRUCT DrawItem = { 0 };
    DrawItem.CtlID = wID;
    OnDrawItem(0, (LPARAM)&DrawItem);

    return 0;
}

void CMainFrame::OnMergeEventDpadUp(GAMEPAD_INPUT_EVENT& event)
{
    if (event.curButtonState.Button & XINPUT_GAMEPAD_DPAD_UP)
    {
        m_lastState.Gamepad.wButtons |= event.curButtonState.Button & XINPUT_GAMEPAD_DPAD_UP;
    }

    DrawButtonItem(IDC_BUTTON_DPAD_UP);
    DoFunction(IDC_BUTTON_DPAD_UP, event);
}

void CMainFrame::OnMergeEventDpadDown(GAMEPAD_INPUT_EVENT& event)
{
    if (event.curButtonState.Button & XINPUT_GAMEPAD_DPAD_DOWN)
    {
        m_lastState.Gamepad.wButtons |= event.curButtonState.Button & XINPUT_GAMEPAD_DPAD_DOWN;
    }

    DrawButtonItem(IDC_BUTTON_DPAD_DOWN);
    DoFunction(IDC_BUTTON_DPAD_DOWN, event);
}

void CMainFrame::OnMergeEventDpadLeft(GAMEPAD_INPUT_EVENT& event)
{
    if (event.curButtonState.Button & XINPUT_GAMEPAD_DPAD_LEFT)
    {
        m_lastState.Gamepad.wButtons |= event.curButtonState.Button & XINPUT_GAMEPAD_DPAD_LEFT;
    }

    DrawButtonItem(IDC_BUTTON_DPAD_LEFT);
    DoFunction(IDC_BUTTON_DPAD_LEFT, event);
}

void CMainFrame::OnMergeEventDpadRight(GAMEPAD_INPUT_EVENT& event)
{
    if (event.curButtonState.Button & XINPUT_GAMEPAD_DPAD_RIGHT)
    {
        m_lastState.Gamepad.wButtons |= event.curButtonState.Button & XINPUT_GAMEPAD_DPAD_RIGHT;
    }

    DrawButtonItem(IDC_BUTTON_DPAD_RIGHT);
    DoFunction(IDC_BUTTON_DPAD_RIGHT, event);
}

void CMainFrame::OnMergeEventBack(GAMEPAD_INPUT_EVENT& event)
{
    if (event.curButtonState.Button & XINPUT_GAMEPAD_BACK)
    {
        m_lastState.Gamepad.wButtons |= event.curButtonState.Button & XINPUT_GAMEPAD_BACK;
    }

    DrawButtonItem(IDC_BUTTON_BACK);
    DoFunction(IDC_BUTTON_BACK, event);
}

void CMainFrame::OnMergeEventStart(GAMEPAD_INPUT_EVENT& event)
{
    if (event.curButtonState.Button & XINPUT_GAMEPAD_START)
    {
        m_lastState.Gamepad.wButtons |= event.curButtonState.Button & XINPUT_GAMEPAD_START;
    }

    DrawButtonItem(IDC_BUTTON_START);
    DoFunction(IDC_BUTTON_START, event);
}

void CMainFrame::OnMergeEventGuide(GAMEPAD_INPUT_EVENT& event)
{
    if (event.curButtonState.Button & XINPUT_GAMEPAD_GUIDE)
    {
        m_lastState.Gamepad.wButtons |= event.curButtonState.Button & XINPUT_GAMEPAD_GUIDE;
    }

    DrawButtonItem(IDC_BUTTON_GUIDE);
    ::Sleep(100);
    DoFunction(IDC_BUTTON_GUIDE, event);
}

void CMainFrame::OnMergeEventA(GAMEPAD_INPUT_EVENT& event)
{
    if (event.curButtonState.Button & XINPUT_GAMEPAD_A)
    {
        m_lastState.Gamepad.wButtons |= event.curButtonState.Button & XINPUT_GAMEPAD_A;
    }

    DrawButtonItem(IDC_BUTTON_A);
    DoFunction(IDC_BUTTON_A, event);
}

void CMainFrame::OnMergeEventB(GAMEPAD_INPUT_EVENT& event)
{
    if (event.curButtonState.Button & XINPUT_GAMEPAD_B)
    {
        m_lastState.Gamepad.wButtons |= event.curButtonState.Button & XINPUT_GAMEPAD_B;
    }

    DrawButtonItem(IDC_BUTTON_B);
    DoFunction(IDC_BUTTON_B, event);
}

void CMainFrame::OnMergeEventX(GAMEPAD_INPUT_EVENT& event)
{
    if (event.curButtonState.Button & XINPUT_GAMEPAD_X)
    {
        m_lastState.Gamepad.wButtons |= event.curButtonState.Button & XINPUT_GAMEPAD_X;
    }

    DrawButtonItem(IDC_BUTTON_X);
    DoFunction(IDC_BUTTON_X, event);
}

void CMainFrame::OnMergeEventY(GAMEPAD_INPUT_EVENT& event)
{
    if (event.curButtonState.Button & XINPUT_GAMEPAD_Y)
    {
        m_lastState.Gamepad.wButtons |= event.curButtonState.Button & XINPUT_GAMEPAD_Y;
    }

    DrawButtonItem(IDC_BUTTON_Y);
    DoFunction(IDC_BUTTON_Y, event);
}

void CMainFrame::OnMergeEventLB(GAMEPAD_INPUT_EVENT& event)
{
    if (event.curButtonState.Button & XINPUT_GAMEPAD_LEFT_SHOULDER)
    {
        m_lastState.Gamepad.wButtons |= event.curButtonState.Button & XINPUT_GAMEPAD_LEFT_SHOULDER;
    }

    DrawButtonItem(IDC_BUTTON_LB);
    DoFunction(IDC_BUTTON_LB, event);
}

void CMainFrame::OnMergeEventRB(GAMEPAD_INPUT_EVENT& event)
{
    if (event.curButtonState.Button & XINPUT_GAMEPAD_RIGHT_SHOULDER)
    {
        m_lastState.Gamepad.wButtons |= event.curButtonState.Button & XINPUT_GAMEPAD_RIGHT_SHOULDER;
    }

    DrawButtonItem(IDC_BUTTON_RB);
    DoFunction(IDC_BUTTON_RB, event);
}

void CMainFrame::OnMergeEventLSB(GAMEPAD_INPUT_EVENT& event)
{
    if (event.curButtonState.Button & XINPUT_GAMEPAD_LEFT_THUMB)
    {
        m_lastState.Gamepad.wButtons |= event.curButtonState.Button & XINPUT_GAMEPAD_LEFT_THUMB;
    }

    DrawButtonItem(IDC_BUTTON_LSB);
    DoFunction(IDC_BUTTON_LSB, event);
}

void CMainFrame::OnMergeEventRSB(GAMEPAD_INPUT_EVENT& event)
{
    if (event.curButtonState.Button & XINPUT_GAMEPAD_RIGHT_THUMB)
    {
        m_lastState.Gamepad.wButtons |= event.curButtonState.Button & XINPUT_GAMEPAD_RIGHT_THUMB;
    }

    DrawButtonItem(IDC_BUTTON_RSB);
    DoFunction(IDC_BUTTON_RSB, event);
}

void CMainFrame::OnMergeEventLT(GAMEPAD_INPUT_EVENT& event)
{
    if (event.bTrigger >= m_lastState.Gamepad.bLeftTrigger)
    {
        m_lastState.Gamepad.bLeftTrigger = event.bTrigger;
    }

    DrawButtonItem(IDC_BUTTON_LT);
    if (m_fVibrationLeft)
    {
        m_Vibration.wLeftMotorSpeed = event.bTrigger * 65536 / 256;
        ::XInputSetState(0, &m_Vibration);
    }

    DoFunction(IDC_BUTTON_LT, event);
}

void CMainFrame::OnMergeEventRT(GAMEPAD_INPUT_EVENT& event)
{
    if (event.bTrigger >= m_lastState.Gamepad.bRightTrigger)
    {
        m_lastState.Gamepad.bRightTrigger = event.bTrigger;
    }

    DrawButtonItem(IDC_BUTTON_RT);
    if (m_fVibrationRight)
    {
        m_Vibration.wRightMotorSpeed = event.bTrigger * 65536 / 256;
        ::XInputSetState(0, &m_Vibration);
    }

    DoFunction(IDC_BUTTON_RT, event);
}

void CMainFrame::OnMergeEventLS(GAMEPAD_INPUT_EVENT& event)
{
    if (event.sAxisX <= m_sThumbLX_Min)
    {
        m_sThumbLX_Min = event.sAxisX;
    }

    if (event.sAxisX >= m_sThumbLX_Max)
    {
        m_sThumbLX_Max = event.sAxisX;
    }

    if (-event.sAxisY <= m_sThumbLY_Min)
    {
        m_sThumbLY_Min = -event.sAxisY;
    }

    if (-event.sAxisY >= m_sThumbLY_Max)
    {
        m_sThumbLY_Max = -event.sAxisY;
    }

    DrawButtonItem(IDC_BUTTON_LEFTSTICK);
    DrawButtonItem(IDC_BUTTON_LSB);
    DrawButtonItem(IDC_STATIC_LEFT_STICK_X);
    DrawButtonItem(IDC_STATIC_LEFT_STICK_Y);
    DoFunction(IDC_BUTTON_LEFTSTICK, event);
}

void CMainFrame::OnMergeEventRS(GAMEPAD_INPUT_EVENT& event)
{
    if (event.sAxisX <= m_sThumbRX_Min)
    {
        m_sThumbRX_Min = event.sAxisX;
    }

    if (event.sAxisX >= m_sThumbRX_Max)
    {
        m_sThumbRX_Max = event.sAxisX;
    }

    if (-event.sAxisY <= m_sThumbRY_Min)
    {
        m_sThumbRY_Min = -event.sAxisY;
    }

    if (-event.sAxisY >= m_sThumbRY_Max)
    {
        m_sThumbRY_Max = -event.sAxisY;
    }

    DrawButtonItem(IDC_BUTTON_RIGHTSTICK);
    DrawButtonItem(IDC_BUTTON_RSB);
    DrawButtonItem(IDC_STATIC_RIGHT_STICK_X);
    DrawButtonItem(IDC_STATIC_RIGHT_STICK_Y);
    DoFunction(IDC_BUTTON_RIGHTSTICK, event);
}

void CMainFrame::InitList()
{
    for (int i = 0; i < _countof(g_ModifierName); i++)
    {
        ::SendMessage(m_hModifier, LB_ADDSTRING, 0, (LPARAM)g_ModifierName[i]);
    }

    for (int i = 0; i < _countof(g_KeysName); i++)
    {
        ::SendMessage(m_hKeys, LB_ADDSTRING, 0, (LPARAM)g_KeysName[i]);
    }

    for (int i = 0; i < _countof(g_MouseName); i++)
    {
        ::SendMessage(m_hMouse, LB_ADDSTRING, 0, (LPARAM)g_MouseName[i]);
    }
}

void CMainFrame::UpdateButtonFunction(WORD wID)
{
    eButtonFunction eType = eButtonFunction::eNone;

    ::EnableWindow(m_hModifier, false);
    ::EnableWindow(m_hKeys, false);
    ::EnableWindow(m_hMouse, false);

    if (IDC_RADIO_NONE == wID)
    {
        eType = eButtonFunction::eNone;
    }

    if (IDC_RADIO_KEY == wID)
    {
        eType = eButtonFunction::eKey;
        ::EnableWindow(m_hModifier, true);
        ::EnableWindow(m_hKeys, true);
    }

    if (IDC_RADIO_MOUSE == wID)
    {
        eType = eButtonFunction::eMouse;
        ::EnableWindow(m_hMouse, true);
    }

    if (0 == m_wFocusID)
    {
        return;
    }

    auto itFind = g_ButtonFunctionList.find(m_wFocusID);
    if (g_ButtonFunctionList.end() != itFind)
    {
        itFind->second.eType = eType;

    }
}

LRESULT CMainFrame::OnModifierChange(WORD wNotify, WORD wID, HWND hWnd)
{
    if (0 == m_wFocusID)
    {
        return TRUE;
    }

    auto itFind = g_ButtonFunctionList.find(m_wFocusID);
    if (itFind != g_ButtonFunctionList.end())
    {
        std::vector<int> vModifier;
        int nIndex = 0;
        for (const auto& item : g_ModifierName)
        {
            LRESULT bSel = ::SendMessage(m_hModifier, LB_GETSEL, nIndex, 0);
            if (bSel)
            {
                vModifier.push_back(nIndex);
            }

            nIndex++;
        }

        itFind->second.vModifier = vModifier;
    }

    return TRUE;
}

LRESULT CMainFrame::OnKeyChange(WORD wNotify, WORD wID, HWND hWnd)
{
    if (0 == m_wFocusID)
    {
        return TRUE;
    }

    auto itFind = g_ButtonFunctionList.find(m_wFocusID);
    if (itFind != g_ButtonFunctionList.end())
    {
        {
            std::vector<int> vModifier;
            int nIndex = 0;
            for (const auto& item : g_ModifierName)
            {
                LRESULT bSel = ::SendMessage(m_hModifier, LB_GETSEL, nIndex, 0);
                if (bSel)
                {
                    vModifier.push_back(nIndex);
                }

                nIndex++;
            }

            itFind->second.vModifier = vModifier;
        }
        {
            std::vector<int> vKeys;
            int nIndex = 0;
            for (const auto& item : g_KeysName)
            {
                LRESULT bSel = ::SendMessage(m_hKeys, LB_GETSEL, nIndex, 0);
                if (bSel)
                {
                    vKeys.push_back(nIndex);
                }

                nIndex++;
            }

            itFind->second.vKeys = vKeys;
        }
    }

    return TRUE;
}

LRESULT CMainFrame::OnMouseChange(WORD wNotify, WORD wID, HWND hWnd)
{
    if (0 == m_wFocusID)
    {
        return TRUE;
    }

    auto itFind = g_ButtonFunctionList.find(m_wFocusID);
    if (itFind != g_ButtonFunctionList.end())
    {
        std::vector<int> vMouse;
        int nIndex = 0;
        for (const auto& item : g_MouseName)
        {
            LRESULT bSel = ::SendMessage(m_hMouse, LB_GETSEL, nIndex, 0);
            if (bSel)
            {
                vMouse.push_back(nIndex);
            }

            nIndex++;
        }

        itFind->second.vMouse = vMouse;
    }

    return TRUE;
}

void CMainFrame::ShowButtonFunction(WORD wID)
{
    ::EnableWindow(m_hModifier, FALSE);
    ::EnableWindow(m_hKeys, FALSE);
    ::EnableWindow(m_hMouse, FALSE);

    if (0 == wID)
    {
    }
    else
    {
        auto itFind = g_ButtonFunctionList.find(wID);
        if (itFind != g_ButtonFunctionList.end())
        {
            CheckButton(IDC_RADIO_NONE, false);
            CheckButton(IDC_RADIO_KEY, false);
            CheckButton(IDC_RADIO_MOUSE, false);

            if (eButtonFunction::eNone == itFind->second.eType)
            {
                CheckButton(IDC_RADIO_NONE, true);
            }
            if (eButtonFunction::eKey == itFind->second.eType)
            {
                CheckButton(IDC_RADIO_KEY, true);
                ::EnableWindow(m_hModifier, TRUE);
                ::EnableWindow(m_hKeys, TRUE);
            }
            if (eButtonFunction::eMouse == itFind->second.eType)
            {
                CheckButton(IDC_RADIO_MOUSE, true);
                ::EnableWindow(m_hMouse, TRUE);
            }

            ::SendMessage(m_hModifier, LB_SETSEL, FALSE, -1);
            for (const auto& item : itFind->second.vModifier)
            {
                LRESULT bSel = ::SendMessage(m_hModifier, LB_SETSEL, TRUE, item);
            }

            ::SendMessage(m_hKeys, LB_SETSEL, FALSE, -1);
            for (const auto& item : itFind->second.vKeys)
            {
                LRESULT bSel = ::SendMessage(m_hKeys, LB_SETSEL, TRUE, item);
            }

            ::SendMessage(m_hMouse, LB_SETSEL, FALSE, -1);
            for (const auto& item : itFind->second.vMouse)
            {
                LRESULT bSel = ::SendMessage(m_hMouse, LB_SETSEL, TRUE, item);
            }
        }
        else
        {
            BUTTON_FUNCTION_INFO info;
            info.eType = eButtonFunction::eNone;

            g_ButtonFunctionList.insert(std::make_pair(wID, info));

            ::SendMessage(m_hKeys, LB_SETSEL, FALSE, -1);
            ::SendMessage(m_hMouse, LB_SETSEL, FALSE, -1);

            ::EnableWindow(m_hModifier, FALSE);
            ::EnableWindow(m_hKeys, FALSE);
            ::EnableWindow(m_hMouse, FALSE);
            CheckButton(IDC_RADIO_NONE, true);
            CheckButton(IDC_RADIO_KEY, false);
            CheckButton(IDC_RADIO_MOUSE, false);
        }
    }
}

void CMainFrame::SaveConfig()
{
    WORD wIDs[] = {
        IDC_BUTTON_LEFTSTICK        ,
        IDC_BUTTON_RIGHTSTICK       ,
        IDC_BUTTON_DPAD_UP          ,
        IDC_BUTTON_DPAD_DOWN        ,
        IDC_BUTTON_DPAD_LEFT        ,
        IDC_BUTTON_DPAD_RIGHT       ,
        IDC_BUTTON_Y                ,
        IDC_BUTTON_A                ,
        IDC_BUTTON_X                ,
        IDC_BUTTON_B                ,
        IDC_BUTTON_BACK             ,
        IDC_BUTTON_START            ,
        IDC_BUTTON_GUIDE            ,
        IDC_BUTTON_LB               ,
        IDC_BUTTON_RB               ,
        IDC_BUTTON_LT               ,
        IDC_BUTTON_RT               ,
    };

    for (auto item : wIDs)
    {
        auto itFind = g_ButtonFunctionList.find(item);
        if (itFind != g_ButtonFunctionList.end())
        {
            DWORD wID = itFind->first;

            _tstring strModifier;
            _tstring strKey;
            _tstring strMouse;

            for (auto item : itFind->second.vModifier)
            {
                strModifier += CStrUtils::Format(_T("%d,"), item);
            }

            for (auto item : itFind->second.vKeys)
            {
                strKey += CStrUtils::Format(_T("%d,"), item);
            }

            for (auto item : itFind->second.vMouse)
            {
                strMouse += CStrUtils::Format(_T("%d,"), item);
            }

            m_config.SetNumber(CStrUtils::Format(_T("%04X"), wID),
                _T("type"), itFind->second.eType);

            m_config.SetString(CStrUtils::Format(_T("%04X"), wID),
                _T("modifier"), strModifier.c_str());

            m_config.SetString(CStrUtils::Format(_T("%04X"), wID),
                _T("keys"), strKey.c_str());

            m_config.SetString(CStrUtils::Format(_T("%04X"), wID),
                _T("mouse"), strMouse.c_str());

        }
    }
}

void CMainFrame::LoadConfig()
{
    WORD wIDs[] = {
        IDC_BUTTON_LEFTSTICK        ,
        IDC_BUTTON_RIGHTSTICK       ,
        IDC_BUTTON_DPAD_UP          ,
        IDC_BUTTON_DPAD_DOWN        ,
        IDC_BUTTON_DPAD_LEFT        ,
        IDC_BUTTON_DPAD_RIGHT       ,
        IDC_BUTTON_Y                ,
        IDC_BUTTON_A                ,
        IDC_BUTTON_X                ,
        IDC_BUTTON_B                ,
        IDC_BUTTON_BACK             ,
        IDC_BUTTON_START            ,
        IDC_BUTTON_GUIDE            ,
        IDC_BUTTON_LB               ,
        IDC_BUTTON_RB               ,
        IDC_BUTTON_LT               ,
        IDC_BUTTON_RT               ,
    };

    for (auto item : wIDs)
    {
        _tstring strModifier = m_config.GetString(CStrUtils::Format(_T("%04X"), item), _T("modifier"));
        _tstring strKey = m_config.GetString(CStrUtils::Format(_T("%04X"), item), _T("keys"));
        _tstring strMouse = m_config.GetString(CStrUtils::Format(_T("%04X"), item), _T("mouse"));

        std::vector<_tstring> vModifier = CStrUtils::SplitStr(strModifier, _T(","));
        std::vector<_tstring> vKeys = CStrUtils::SplitStr(strKey, _T(","));
        std::vector<_tstring> vMouse = CStrUtils::SplitStr(strMouse, _T(","));

        BUTTON_FUNCTION_INFO info;
        info.eType = (eButtonFunction)m_config.GetNumber(CStrUtils::Format(_T("%04X"), item),
            _T("type"), eButtonFunction::eNone);

        for (const auto& item : vModifier)
        {
            info.vModifier.push_back(_tcstol(item.c_str(), NULL, 10));
        }

        for (const auto& item : vKeys)
        {
            info.vKeys.push_back(_tcstol(item.c_str(), NULL, 10));
        }

        for (const auto& item : vMouse)
        {
            info.vMouse.push_back(_tcstol(item.c_str(), NULL, 10));
        }

        g_ButtonFunctionList.insert(std::make_pair(item, info));
    }
}

void CMainFrame::DoMouseMove(int x, int y)
{
    enum eDirectionType
    {
        eUp = 1,
        eDown = 2,
        eLeft = 4,
        eRight = 8,
    };

    int nStickType = 0;
    nStickType |= y > MOUSE_MOVE_THRESHOLD ? eUp : 0;
    nStickType |= y < -MOUSE_MOVE_THRESHOLD ? eDown : 0;

    nStickType |= x < -MOUSE_MOVE_THRESHOLD ? eLeft : 0;
    nStickType |= x > MOUSE_MOVE_THRESHOLD ? eRight : 0;


    float left = 0;
    float up = 0;
    float right = 0;
    float down = 0;

    int limit = (double)(32767 - MOUSE_MOVE_THRESHOLD);
    int speed_level = 10;
    int speed = limit / speed_level;
    int ThumbLX = x;
    int ThumbLY = y;

    if (ThumbLX < 0)
    {
        if (ThumbLX < -MOUSE_MOVE_THRESHOLD)
        {
            ThumbLX += MOUSE_MOVE_THRESHOLD;
            ThumbLX -= speed;
        }
        else
        {
            ThumbLX = 0;
        }
    }

    if (ThumbLX > 0)
    {
        if (ThumbLX > MOUSE_MOVE_THRESHOLD)
        {
            ThumbLX -= MOUSE_MOVE_THRESHOLD;
            ThumbLX += speed;
        }
        else
        {
            ThumbLX = 0;
        }
    }

    if (ThumbLY < 0)
    {
        if (ThumbLY < -MOUSE_MOVE_THRESHOLD)
        {
            ThumbLY += MOUSE_MOVE_THRESHOLD;
            ThumbLY -= speed;
        }
        else
        {
            ThumbLY = 0;
        }
    }

    if (ThumbLY > 0)
    {
        if (ThumbLY > MOUSE_MOVE_THRESHOLD)
        {
            ThumbLY -= MOUSE_MOVE_THRESHOLD;
            ThumbLY += speed;
        }
        else
        {
            ThumbLY = 0;
        }
    }

    if (ThumbLX < 0)
    {
        left = abs(ThumbLX / speed);
    }
    if (ThumbLX > 0)
    {
        right = abs(ThumbLX / speed);
    }

    if (ThumbLY < 0)
    {
        down = abs(ThumbLY / speed);
    }
    if (ThumbLY > 0)
    {
        up = abs(ThumbLY / speed);
    }

    float dx = (right - left);
    float dy = (down - up);

    CInputUtils::MouseMove(dx, dy, false);
}

void CMainFrame::DoMouseWheel(int x, int y)
{
    float left = 0;
    float up = 0;
    float right = 0;
    float down = 0;

    if (x < -MOUSE_SRCOLL_THRESHOLD)
    {
        left = 1;
    }
    if (x > MOUSE_SRCOLL_THRESHOLD)
    {
        right = 1;
    }

    if (y < -MOUSE_SRCOLL_THRESHOLD)
    {
        down = 1;
    }
    if (y > MOUSE_SRCOLL_THRESHOLD)
    {
        up = 1;
    }

    static float last_dx = 0;
    static float last_dy = 0;
    float dx = (right - left);
    float dy = (down - up);

    bool bHoriz = false;
    if (abs(dx) > abs(dy))
    {
        bHoriz = true;
    }

    last_dx = dx;
    last_dy = dy;

    if (0 != dx || 0 != dy)
    {
        CInputUtils::MouseWheel(-dy, dx);
    }
}

void CMainFrame::DoFunction(WORD wID, GAMEPAD_INPUT_EVENT& event)
{
    auto itFInd = g_ButtonFunctionList.find(wID);
    if (itFInd != g_ButtonFunctionList.end())
    {
        if (IDC_BUTTON_LEFTSTICK == wID && eButtonFunction::eMouse == itFInd->second.eType)
        {
            bool fHasMouseMove = false;
            bool fHasMouseWheel = false;

            for (const auto& item: itFInd->second.vMouse)
            {
                if (item == eMouseType::eMouseMove)
                {
                    fHasMouseMove = true;
                }
                if (item == eMouseType::eMouseWheel)
                {
                    fHasMouseWheel = true;
                }
            }

            if (fHasMouseMove)
            {
                DoMouseMove(m_CurXInputStateMerge.Gamepad.sThumbLX, m_CurXInputStateMerge.Gamepad.sThumbLY);
            }

            if (fHasMouseWheel)
            {
                DoMouseWheel(m_CurXInputStateMerge.Gamepad.sThumbLX, m_CurXInputStateMerge.Gamepad.sThumbLY);
            }

            return;
        }

        if (IDC_BUTTON_RIGHTSTICK == wID && eButtonFunction::eMouse == itFInd->second.eType)
        {
            bool fHasMouseMove = false;
            bool fHasMouseWheel = false;

            for (const auto& item: itFInd->second.vMouse)
            {
                if (item == eMouseType::eMouseMove)
                {
                    fHasMouseMove = true;
                }
                if (item == eMouseType::eMouseWheel)
                {
                    fHasMouseWheel = true;
                }
            }

            if (fHasMouseMove)
            {
                DoMouseMove(m_CurXInputStateMerge.Gamepad.sThumbRX, m_CurXInputStateMerge.Gamepad.sThumbRY);
            }

            if (fHasMouseWheel)
            {
                DoMouseWheel(m_CurXInputStateMerge.Gamepad.sThumbRX, m_CurXInputStateMerge.Gamepad.sThumbRY);
            }

            return;
        }

        if (eButtonFunction::eMouse == itFInd->second.eType)
        {
            bool fHasMouseLeft = false;
            bool fHasMouseRight = false;
            bool fHasMouseMiddle = false;

            for (const auto& item: itFInd->second.vMouse)
            {
                if (item == eMouseType::eMouseLeft)
                {
                    fHasMouseLeft = true;
                }

                if (item == eMouseType::eMouseRight)
                {
                    fHasMouseRight = true;
                }

                if (item == eMouseType::eMouseMiddle)
                {
                    fHasMouseMiddle = true;
                }
            }

            if (fHasMouseLeft)
            {
                CInputUtils::MouseKey(eInputMouseButton::eMButton_Left, event.curButtonEvent.Down, event.curButtonEvent.Up);
            }

            if (fHasMouseRight)
            {
                CInputUtils::MouseKey(eInputMouseButton::eMButton_Right, event.curButtonEvent.Down, event.curButtonEvent.Up);
            }

            if (fHasMouseMiddle)
            {
                CInputUtils::MouseKey(eInputMouseButton::eMButton_Middle, event.curButtonEvent.Down, event.curButtonEvent.Up);
            }
        }

        if (eButtonFunction::eKey == itFInd->second.eType)
        {
            if (event.curButtonEvent.Down)
            {
                for (const auto& item : itFInd->second.vModifier)
                {
                    CInputUtils::KeyboardByName(g_ModifierName[item], event.curButtonEvent.Down, event.curButtonEvent.Up);
                }

                for (const auto& item : itFInd->second.vKeys)
                {
                    CInputUtils::KeyboardByName(g_KeysName[item], event.curButtonEvent.Down, event.curButtonEvent.Up);
                }
            }

            if (event.curButtonEvent.Hold)
            {
                for (const auto& item : itFInd->second.vKeys)
                {
                    CInputUtils::KeyboardByName(g_KeysName[item], event.curButtonEvent.uTime > 500, event.curButtonEvent.Up);
                }
            }

            if (event.curButtonEvent.Up)
            {
                for (const auto& item : itFInd->second.vKeys)
                {
                    CInputUtils::KeyboardByName(g_KeysName[item], event.curButtonEvent.Down, event.curButtonEvent.Up);
                }

                for (const auto& item : itFInd->second.vModifier)
                {
                    CInputUtils::KeyboardByName(g_ModifierName[item], event.curButtonEvent.Down, event.curButtonEvent.Up);
                }
            }
        }
    }
}

资源相关

resource.h

cpp 复制代码
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ 生成的包含文件。
// 供 XboxAssistant.rc 使用
//
#define IDI_ICON                        102
#define IDD_DIALOG_MAIN                 103
#define IDR_ACCELERATOR                 105
#define IDC_BUTTON_LEFTSTICK            1001
#define IDC_BUTTON_RIGHTSTICK           1002
#define IDC_BUTTON_DPAD_UP              1003
#define IDC_BUTTON_DPAD_DOWN            1004
#define IDC_BUTTON_DPAD_LEFT            1005
#define IDC_BUTTON_DPAD_RIGHT           1006
#define IDC_BUTTON_Y                    1007
#define IDC_BUTTON_A                    1008
#define IDC_BUTTON_X                    1009
#define IDC_BUTTON_B                    1010
#define IDC_BUTTON_BACK                 1011
#define IDC_BUTTON_START                1012
#define IDC_BUTTON_GUIDE                1013
#define IDC_BUTTON_LB                   1014
#define IDC_BUTTON_RB                   1015
#define IDC_BUTTON_LT                   1017
#define IDC_BUTTON_RT                   1018
#define IDC_STATIC_LEFT_STICK_X         1019
#define IDC_STATIC_RIGHT_STICK_Y        1020
#define IDC_BUTTON_RESET                1021
#define IDC_CHECK_VIBRATION_LEFT        1022
#define IDC_CHECK_VIBRATION_RIGHT       1023
#define IDC_STATIC_LEFT_STICK_Y         1024
#define IDC_STATIC_RIGHT_STICK_X        1025
#define IDC_RADIO_KEY                   1028
#define IDC_LIST_KEYS                   1029
#define IDC_LIST_MOUSE                  1030
#define IDC_RADIO_MOUSE                 1031
#define IDC_RADIO_NONE                  1032
#define IDC_LIST_MODIFIER               1033
#define IDC_BUTTON_LSB                   1034
#define IDC_BUTTON_RSB2                  1035
#define IDC_BUTTON_RSB                   1035

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE        106
#define _APS_NEXT_COMMAND_VALUE         40003
#define _APS_NEXT_CONTROL_VALUE         1035
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

XboxAssistant.rc

cpp 复制代码
// Microsoft Visual C++ generated resource script.
//
#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
/
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"

/
#undef APSTUDIO_READONLY_SYMBOLS

/
// 中文(简体,中国) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_CHS)
LANGUAGE LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED

#ifdef APSTUDIO_INVOKED
/
//
// TEXTINCLUDE
//

1 TEXTINCLUDE 
BEGIN
    "resource.h\0"
END

2 TEXTINCLUDE 
BEGIN
    "#include ""winres.h""\r\n"
    "\0"
END

3 TEXTINCLUDE 
BEGIN
    "\r\n"
    "\0"
END

#endif    // APSTUDIO_INVOKED


/
//
// Icon
//

// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_ICON                ICON                    "icon.ico"


/
//
// Dialog
//

IDD_DIALOG_MAIN DIALOGEX 0, 0, 442, 243
STYLE DS_SETFONT | DS_MODALFRAME | WS_MINIMIZEBOX | WS_POPUP | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU
CAPTION "XboxAssistant"
FONT 12, "楷体", 700, 0, 0x86
BEGIN
    PUSHBUTTON      "",IDC_BUTTON_LSB,50,81,8,8,NOT WS_VISIBLE
    PUSHBUTTON      "",IDC_BUTTON_RSB,196,161,8,8,NOT WS_VISIBLE
    CONTROL         "LT",IDC_BUTTON_LT,"Button",BS_OWNERDRAW | NOT WS_VISIBLE | WS_TABSTOP,7,7,19,183
    CONTROL         "LB",IDC_BUTTON_LB,"Button",BS_OWNERDRAW | NOT WS_VISIBLE | WS_TABSTOP,29,7,33,14
    CONTROL         "RB",IDC_BUTTON_RB,"Button",BS_OWNERDRAW | NOT WS_VISIBLE | WS_TABSTOP,192,7,33,14
    CONTROL         "RT",IDC_BUTTON_RT,"Button",BS_OWNERDRAW | NOT WS_VISIBLE | WS_TABSTOP,230,7,19,183
    LTEXT           "X: -32767",IDC_STATIC_LEFT_STICK_X,29,31,50,8,NOT WS_VISIBLE
    LTEXT           "Y: -32767",IDC_STATIC_LEFT_STICK_Y,29,44,50,8,NOT WS_VISIBLE
    CONTROL         "",IDC_BUTTON_LEFTSTICK,"Button",BS_OWNERDRAW | NOT WS_VISIBLE | WS_TABSTOP,29,60,50,50
    CONTROL         "Guide",IDC_BUTTON_GUIDE,"Button",BS_OWNERDRAW | NOT WS_VISIBLE | WS_TABSTOP,119,48,24,24
    CONTROL         "",IDC_BUTTON_BACK,"Button",BS_OWNERDRAW | NOT WS_VISIBLE | WS_TABSTOP,100,73,19,18
    CONTROL         "",IDC_BUTTON_START,"Button",BS_OWNERDRAW | NOT WS_VISIBLE | WS_TABSTOP,144,73,19,18
    CONTROL         "Y",IDC_BUTTON_Y,"Button",BS_OWNERDRAW | NOT WS_VISIBLE | WS_TABSTOP,193,33,16,16
    CONTROL         "X",IDC_BUTTON_X,"Button",BS_OWNERDRAW | NOT WS_VISIBLE | WS_TABSTOP,178,48,16,16
    CONTROL         "A",IDC_BUTTON_A,"Button",BS_OWNERDRAW | NOT WS_VISIBLE | WS_TABSTOP,193,63,16,16
    CONTROL         "B",IDC_BUTTON_B,"Button",BS_OWNERDRAW | NOT WS_VISIBLE | WS_TABSTOP,209,48,16,16
    CONTROL         "Up",IDC_BUTTON_DPAD_UP,"Button",BS_OWNERDRAW | NOT WS_VISIBLE | WS_TABSTOP,47,134,19,18
    CONTROL         "Left",IDC_BUTTON_DPAD_LEFT,"Button",BS_OWNERDRAW | NOT WS_VISIBLE | WS_TABSTOP,29,153,19,18
    CONTROL         "Down",IDC_BUTTON_DPAD_DOWN,"Button",BS_OWNERDRAW | NOT WS_VISIBLE | WS_TABSTOP,47,172,19,18
    CONTROL         "Right",IDC_BUTTON_DPAD_RIGHT,"Button",BS_OWNERDRAW | NOT WS_VISIBLE | WS_TABSTOP,65,153,19,18
    LTEXT           "X: -32767",IDC_STATIC_RIGHT_STICK_X,175,116,50,8,NOT WS_VISIBLE
    LTEXT           "Y: -32767",IDC_STATIC_RIGHT_STICK_Y,175,129,50,8,NOT WS_VISIBLE
    CONTROL         "",IDC_BUTTON_RIGHTSTICK,"Button",BS_OWNERDRAW | NOT WS_VISIBLE | WS_TABSTOP,175,140,50,50
    CONTROL         "Vibration",IDC_CHECK_VIBRATION_LEFT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,194,52,10
    PUSHBUTTON      "Reset",IDC_BUTTON_RESET,100,212,70,25
    CONTROL         "Vibration",IDC_CHECK_VIBRATION_RIGHT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,197,194,52,10
    CONTROL         "None",IDC_RADIO_NONE,"Button",BS_AUTORADIOBUTTON | WS_GROUP,259,12,32,10
    CONTROL         "Keyboard",IDC_RADIO_KEY,"Button",BS_AUTORADIOBUTTON,358,12,48,10
    CONTROL         "Mouse",IDC_RADIO_MOUSE,"Button",BS_AUTORADIOBUTTON,296,12,36,10
    LISTBOX         IDC_LIST_KEYS,380,32,52,203,LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP
    LISTBOX         IDC_LIST_MOUSE,260,32,52,203,LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP
    LISTBOX         IDC_LIST_MODIFIER,326,32,52,203,LBS_NOINTEGRALHEIGHT | LBS_EXTENDEDSEL | WS_VSCROLL | WS_TABSTOP
END


/
//
// DESIGNINFO
//

#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
    IDD_DIALOG_MAIN, DIALOG
    BEGIN
        BOTTOMMARGIN, 242
    END
END
#endif    // APSTUDIO_INVOKED


/
//
// AFX_DIALOG_LAYOUT
//

IDD_DIALOG_MAIN AFX_DIALOG_LAYOUT
BEGIN
    0
END


/
//
// Accelerator
//

IDR_ACCELERATOR ACCELERATORS
BEGIN
    "R",            IDC_BUTTON_RESET,       VIRTKEY, CONTROL, NOINVERT
END

#endif    // 中文(简体,中国) resources
/



#ifndef APSTUDIO_INVOKED
/
//
// Generated from the TEXTINCLUDE 3 resource.
//


/
#endif    // not APSTUDIO_INVOKED

工程结构

运行效果

源码仓库

FlameCyclone/XboxAssistantEx (gitee.com)

相关推荐
redcocal6 分钟前
地平线内推码 kbrfck
c++·嵌入式硬件·mcu·算法·fpga开发·求职招聘
归去来兮★16 分钟前
c++面向对象
java·开发语言·c++
Trouvaille ~27 分钟前
【C++篇】C++类与对象深度解析(四):初始化列表、类型转换与static成员详解
c++·类型转换·类和对象·面向对象编程·static·初始化列表·开发者指南
杨~friendship43 分钟前
Ubuntu上使用qt和opencv显示图像
linux·开发语言·c++·qt·opencv·ubuntu
CS小麻瓜1 小时前
Web植物管理系统-下位机部分
c++·嵌入式硬件·湖南大学
界面开发小八哥2 小时前
「Qt Widget中文示例指南」如何实现一个系统托盘图标?(二)
开发语言·c++·qt·用户界面
月夕花晨3742 小时前
C++学习笔记(24)
c++·笔记·学习
疑惑的杰瑞2 小时前
[乱码]确保命令行窗口与主流集成开发环境(IDE)统一采用UTF-8编码,以规避乱码问题
java·c++·vscode·python·eclipse·sublime text·visual studio
running thunderbolt2 小时前
C++:类和对象全解
c语言·开发语言·c++·算法
Zlb22142 小时前
Windows下使用qemu
windows