键盘鼠标模拟输入(Win32, C++)

 CInputUtils.h

#pragma once

#include <windows.h>
#include <tchar.h>
#include <string>
#include <map>

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

typedef struct _KBDATA_INFO KBDATA_INFO;

typedef struct _KBDATA_INFO {
    WORD vkCode;
    WORD scanCode;
    DWORD flags;

    _KBDATA_INFO() :vkCode(0), scanCode(0), flags(0) {};

    _KBDATA_INFO(WORD vk, WORD sc, DWORD f) : vkCode(vk), scanCode(sc), flags(f) {};

    _KBDATA_INFO(const _KBDATA_INFO& r) :vkCode(r.vkCode), scanCode(r.scanCode), flags(r.flags) {}

    bool operator == (const _KBDATA_INFO& r) const
    {
        return (this->scanCode == r.scanCode) && (this->flags & 0x01) == (r.flags & 0x01);
    }

    bool operator != (const _KBDATA_INFO& r) const
    {
        return !(*this == r);
    }

    bool operator < (const _KBDATA_INFO& r) const
    {
        if (this->scanCode != r.scanCode) return this->scanCode < r.scanCode;
        return (this->flags & 0x01) < (r.flags & 0x01);
    }

    void operator=(const _KBDATA_INFO& r)
    {
        this->vkCode = r.vkCode;
        this->scanCode = r.scanCode;
        this->flags = r.flags;
    }

} KBDATA_INFO, FAR* LPKBDATA_INFO, * PKBDATA_INFO;

class CInputUtils
{
public:

    //
    // @brief: 发送按键
    // @param: wVk          虚键码
    // @param: wScan        扫描码
    // @param: bExtended    是否扩展键
    // @param: bDown        是否要按下
    // @param: bUp          是否要弹起
    // @param: bScan        是否扫描码(启用后忽略虚键码)
    // @ret: bool           操作成功返回true
    static bool Keyboard(WORD wVk, WORD wScan, bool bExtended = false, bool bDown = true, bool bUp = true, bool bScan = false);

    //
    // @brief: 发送按键
    // @param: strKey       按键名
    // @param: bDown        是否要按下
    // @param: bUp          是否要弹起
    // @ret: bool           操作成功返回true
    static bool Keyboard(_tstring strKey, bool bDown = true, bool bUp = true);

    //
    // @brief: 发送字符
    // @param: ch           字符
    // @ret: bool           操作成功返回true
    static bool KeyboardChar(TCHAR ch);

    //
    // @brief: 发送字符串
    // @param: strText      字符
    // @ret: bool           操作成功返回true
    static bool KeyboardText(_tstring strText);

    //
    // @brief: 鼠标移动
    // @param: x            横坐标
    // @param: y            纵坐标
    // @param: bAbsolute    是否绝对坐标, 如果为true, 移动到指定坐标, 否则相对于当前坐标进行移动
    // @ret: bool           操作成功返回true
	static bool MouseMove(LONG x, LONG y, bool bAbsolute = true);

    //
    // @brief: 鼠标按键
    // @param: bLeft        鼠标左键
    // @param: bRight       鼠标右键
    // @param: bMiddle      鼠标中键
    // @param: bDown        按下按键
    // @param: bUp          弹起按键
    // @ret: bool           操作成功返回true
	static bool MouseKey(bool bLeft, bool bRight, bool bMiddle, bool bDown = true, bool bUp = true);

    //
    // @brief: 鼠标滚轮向前滚动
    // @param: nSpeed       速度
    // @ret: bool           操作成功返回true
	static bool MouseWheelForward(LONG nSpeed = 1);

    //
    // @brief: 鼠标滚轮向后滚动
    // @param: nSpeed       速度
    // @ret: bool           操作成功返回true
	static bool MouseWheelBackward(LONG nSpeed = 1);

private:
    static std::map<_tstring, KBDATA_INFO> m_KeyMap;
    static std::map<DWORD, _tstring> m_UsbKeyMap;
};

CInputUtils.cpp

#include "CInputUtils.h"
#include <iostream>

std::map<_tstring, KBDATA_INFO> CInputUtils::m_KeyMap =
{
    { _T("Esc"), KBDATA_INFO(0x1B, 0x01, 0)},
    { _T("F1"),  KBDATA_INFO(0x70, 0x3B, 0)},
    { _T("F2"),  KBDATA_INFO(0x71, 0x3C, 0)},
    { _T("F3"),  KBDATA_INFO(0x72, 0x3D, 0)},
    { _T("F4"),  KBDATA_INFO(0x73, 0x3E, 0)},
    { _T("F5"),  KBDATA_INFO(0x74, 0x3F, 0)},
    { _T("F6"),  KBDATA_INFO(0x75, 0x40, 0)},
    { _T("F7"),  KBDATA_INFO(0x76, 0x41, 0)},
    { _T("F8"),  KBDATA_INFO(0x77, 0x42, 0)},
    { _T("F9"),  KBDATA_INFO(0x78, 0x43, 0)},
    { _T("F10"), KBDATA_INFO(0x79, 0x44, 0)},
    { _T("F11"), KBDATA_INFO(0x7A, 0x57, 0)},
    { _T("F12"), KBDATA_INFO(0x7B, 0x58, 0)},
    { _T("F15"), KBDATA_INFO(0x7E, 0x66, 0)},
    { _T("F16"), KBDATA_INFO(0x7F, 0x67, 0)},
    { _T("F17"), KBDATA_INFO(0x80, 0x68, 0)},

    { _T("`"),   KBDATA_INFO(0xC0, 0x29, 0)},
    { _T("1"),   KBDATA_INFO(0x31, 0x02, 0)},
    { _T("2"),   KBDATA_INFO(0x32, 0x03, 0)},
    { _T("3"),   KBDATA_INFO(0x33, 0x04, 0)},
    { _T("4"),   KBDATA_INFO(0x34, 0x05, 0)},
    { _T("5"),   KBDATA_INFO(0x35, 0x06, 0)},
    { _T("6"),   KBDATA_INFO(0x36, 0x07, 0)},
    { _T("7"),   KBDATA_INFO(0x37, 0x08, 0)},
    { _T("8"),   KBDATA_INFO(0x38, 0x09, 0)},
    { _T("9"),   KBDATA_INFO(0x39, 0x0A, 0)},
    { _T("0"),   KBDATA_INFO(0x30, 0x0B, 0)},
    { _T("-"),   KBDATA_INFO(0xBD, 0x0C, 0)},
    { _T("="),   KBDATA_INFO(0xBB, 0x0D, 0)},
    { _T("Backspace"), KBDATA_INFO(0x08, 0x0E, 0)},

    { _T("LCtrl"), KBDATA_INFO(0xA2, 0x1D, 0)},
    { _T("RCtrl"), KBDATA_INFO(0xA3, 0x1D, 1)},
    { _T("LAlt"), KBDATA_INFO(0xA4, 0x38, 0)},
    { _T("RAlt"), KBDATA_INFO(0xA5, 0x38, 1)},
    { _T("LWin"), KBDATA_INFO(0x5B, 0x5B, 1)},
    { _T("RWin"), KBDATA_INFO(0x5C, 0x5C, 1)},
    { _T("LShift"), KBDATA_INFO(0xA0, 0x2A, 0)},
    { _T("RShift"), KBDATA_INFO(0xA1, 0x36, 1)},

    { _T("Appcation"), KBDATA_INFO(0x5D, 0x5D, 1)},

    { _T("Tab"), KBDATA_INFO(0x09, 0x0F, 0)},
    { _T("Space"), KBDATA_INFO(0x20, 0x39, 0)},
    { _T("Enter"), KBDATA_INFO(0x0d, 0x1C, 0)},

    { _T("["), KBDATA_INFO(0xDB, 0x1A, 0)},
    { _T("]"), KBDATA_INFO(0xDD, 0x1B, 0)},
    { _T("\\"), KBDATA_INFO(0xDC, 0x2B, 0)},

    { _T(";"), KBDATA_INFO(0xBA, 0x27, 0)},
    { _T("\'"), KBDATA_INFO(0xDE, 0x28, 0)},

    { _T(","), KBDATA_INFO(0xBC, 0x33, 0)},
    { _T("."), KBDATA_INFO(0xBE, 0x34, 0)},
    { _T("/"), KBDATA_INFO(0xBF, 0x35, 0)},

    { _T("A"), KBDATA_INFO('A', 0x1E, 0)},
    { _T("B"), KBDATA_INFO('B', 0x30, 0)},
    { _T("C"), KBDATA_INFO('C', 0x2E, 0)},
    { _T("D"), KBDATA_INFO('D', 0x20, 0)},
    { _T("E"), KBDATA_INFO('E', 0x12, 0)},
    { _T("F"), KBDATA_INFO('F', 0x21, 0)},
    { _T("G"), KBDATA_INFO('G', 0x22, 0)},
    { _T("H"), KBDATA_INFO('H', 0x23, 0)},
    { _T("I"), KBDATA_INFO('I', 0x17, 0)},
    { _T("J"), KBDATA_INFO('J', 0x24, 0)},
    { _T("K"), KBDATA_INFO('K', 0x25, 0)},
    { _T("L"), KBDATA_INFO('L', 0x26, 0)},
    { _T("M"), KBDATA_INFO('M', 0x32, 0)},
    { _T("N"), KBDATA_INFO('N', 0x31, 0)},
    { _T("O"), KBDATA_INFO('O', 0x18, 0)},
    { _T("P"), KBDATA_INFO('P', 0x19, 0)},
    { _T("Q"), KBDATA_INFO('Q', 0x10, 0)},
    { _T("R"), KBDATA_INFO('R', 0x13, 0)},
    { _T("S"), KBDATA_INFO('S', 0x1F, 0)},
    { _T("T"), KBDATA_INFO('T', 0x14, 0)},
    { _T("U"), KBDATA_INFO('U', 0x16, 0)},
    { _T("V"), KBDATA_INFO('V', 0x2F, 0)},
    { _T("W"), KBDATA_INFO('W', 0x11, 0)},
    { _T("X"), KBDATA_INFO('X', 0x2D, 0)},
    { _T("Y"), KBDATA_INFO('Y', 0x15, 0)},
    { _T("Z"), KBDATA_INFO('Z', 0x2C, 0)},

    { _T("Up"),    KBDATA_INFO(0x26, 0x48, 1)},
    { _T("Down"),  KBDATA_INFO(0x28, 0x50, 1)},
    { _T("Left"),  KBDATA_INFO(0x25, 0x4B, 1)},
    { _T("Right"), KBDATA_INFO(0x27, 0x4D, 1)},

    { _T("Num Up"),    KBDATA_INFO(0x26, 0x48, 0)},
    { _T("Num Down"),  KBDATA_INFO(0x28, 0x50, 0)},
    { _T("Num Left"),  KBDATA_INFO(0x25, 0x4B, 0)},
    { _T("Num Right"), KBDATA_INFO(0x27, 0x4D, 0)},

    { _T("Insert"),    KBDATA_INFO(0x2d, 0x52, 1)},
    { _T("Home"),      KBDATA_INFO(0x24, 0x47, 1)},
    { _T("Page Up"),   KBDATA_INFO(0x21, 0x49, 1)},
    { _T("Delete"),    KBDATA_INFO(0x2E, 0x53, 1) },
    { _T("End"),       KBDATA_INFO(0x23, 0x4F, 1)},
    { _T("Page Down"), KBDATA_INFO(0x22, 0x51, 1)},

    { _T("Prnt Scrn"), KBDATA_INFO(0x2C, 0x37, 1)},
    { _T("Scroll Lock"), KBDATA_INFO(0x91, 0x46, 0)},
    { _T("Num Lock"),  KBDATA_INFO(0x90, 0x45, 1)},
    { _T("Caps Lock"), KBDATA_INFO(0x14, 0x3A, 0) },
    { _T("Pause"),     KBDATA_INFO(0x13, 0x45, 1)},

    { _T("Num 0"), KBDATA_INFO(0x60, 0x52, 0) },
    { _T("Num 1"), KBDATA_INFO(0x61, 0x4F, 0) },
    { _T("Num 2"), KBDATA_INFO(0x62, 0x50, 0) },
    { _T("Num 3"), KBDATA_INFO(0x63, 0x51, 0) },
    { _T("Num 4"), KBDATA_INFO(0x64, 0x4B, 0) },
    { _T("Num 5"), KBDATA_INFO(0x65, 0x4C, 0) },
    { _T("Num 6"), KBDATA_INFO(0x66, 0x4D, 0) },
    { _T("Num 7"), KBDATA_INFO(0x67, 0x47, 0) },
    { _T("Num 8"), KBDATA_INFO(0x68, 0x48, 0) },
    { _T("Num 9"), KBDATA_INFO(0x69, 0x49, 0) },

    { _T("Num Home"), KBDATA_INFO(0x24, 0x47, 0) },
    { _T("Num End"), KBDATA_INFO(0x23, 0x4F, 0) },
    { _T("Num Page Up"),   KBDATA_INFO(0x21, 0x49, 0) },
    { _T("Num Page Down"), KBDATA_INFO(0x22, 0x51, 0) },

    { _T("Clear"), KBDATA_INFO(0x0C, 0x4C, 0) },

    { _T("Num /"), KBDATA_INFO(0x6f, 0x35, 1) },
    { _T("Num *"), KBDATA_INFO(0x6A, 0x37, 0) },
    { _T("Num -"), KBDATA_INFO(0x6D, 0x4A, 0) },
    { _T("Num +"), KBDATA_INFO(0x6B, 0x4E, 0) },
    { _T("Num Enter"), KBDATA_INFO(0x0B, 0x1C, 1) },
    { _T("Num Del"), KBDATA_INFO(0x2E, 0x53, 0) },
    { _T("Num Insert"),     KBDATA_INFO(0x2D, 0x52, 0) },
    { _T("Num ."),     KBDATA_INFO(0x6E, 0x53, 0) },

};  //118个按键

//USB按键映射表
std::map<DWORD, _tstring> CInputUtils::m_UsbKeyMap =
{
    {0x04, _T("A")},
    {0x05, _T("B")},
    {0x06, _T("C")},
    {0x07, _T("D")},
    {0x08, _T("E")},
    {0x09, _T("F")},
    {0x0A, _T("G")},
    {0x0B, _T("H")},
    {0x0C, _T("I")},
    {0x0D, _T("J")},
    {0x0E, _T("K")},
    {0x0F, _T("L")},
    {0x10, _T("M")},
    {0x11, _T("N")},
    {0x12, _T("O")},
    {0x13, _T("P")},
    {0x14, _T("Q")},
    {0x15, _T("R")},
    {0x16, _T("S")},
    {0x17, _T("T")},
    {0x18, _T("U")},
    {0x19, _T("V")},
    {0x1A, _T("W")},
    {0x1B, _T("X")},
    {0x1C, _T("Y")},
    {0x1D, _T("Z")},
    {0x1E, _T("1")},
    {0x1F, _T("2")},
    {0x20, _T("3")},
    {0x21, _T("4")},
    {0x22, _T("5")},
    {0x23, _T("6")},
    {0x24, _T("7")},
    {0x25, _T("8")},
    {0x26, _T("9")},
    {0x27, _T("0")},
    {0x28, _T("Enter")},
    {0x29, _T("Esc")},
    {0x2A, _T("Backspace")},
    {0x2B, _T("Tab")},
    {0x2C, _T("Space")},
    {0x2D, _T("-")},
    {0x2E, _T("=")},
    {0x2F, _T("[")},
    {0x30, _T("]")},
    {0x31, _T("\\")},
    {0x33, _T(";")},
    {0x34, _T("\'")},
    {0x35, _T("`")},
    {0x36, _T(",")},
    {0x37, _T(".")},
    {0x38, _T("/")},
    {0x39, _T("Caps Lock")},
    {0x3A, _T("F1")},
    {0x3B, _T("F2")},
    {0x3C, _T("F3")},
    {0x3D, _T("F4")},
    {0x3E, _T("F5")},
    {0x3F, _T("F6")},
    {0x40, _T("F7")},
    {0x41, _T("F8")},
    {0x42, _T("F9")},
    {0x43, _T("F10")},
    {0x44, _T("F11")},
    {0x45, _T("F12")},
    {0x46, _T("Prnt Scrn")},
    {0x47, _T("Scroll Lock")},
    {0x48, _T("Pause")},
    {0x49, _T("Insert")},
    {0x4A, _T("Home")},
    {0x4B, _T("Page Up")},
    {0x4C, _T("Delete")},
    {0x4D, _T("End")},
    {0x4E, _T("Page Down")},
    {0x4F, _T("Right")},
    {0x50, _T("Left")},
    {0x51, _T("Down")},
    {0x52, _T("Up")},
    {0x53, _T("Num Lock")},
    {0x54, _T("Num /")},
    {0x55, _T("Num *")},
    {0x56, _T("Num -")},
    {0x57, _T("Num +")},
    {0x58, _T("Num Enter")},
    {0x59, _T("Num 1")},
    {0x5A, _T("Num 2")},
    {0x5B, _T("Num 3")},
    {0x5C, _T("Num 4")},
    {0x5D, _T("Num 5")},
    {0x5E, _T("Num 6")},
    {0x5F, _T("Num 7")},
    {0x60, _T("Num 8")},
    {0x61, _T("Num 9")},
    {0x62, _T("Num 0")},
    {0x63, _T("Num .")},
    {0x64, _T("\\(Non-US)")},
    {0x65, _T("Appcation")}
};

bool CInputUtils::Keyboard(WORD wVk, WORD wScan, bool bExtended/* = false*/, bool bDown/* = true*/, bool bUp/* = true*/, bool bScan/* = false*/)
{
    INPUT inputs[0x02] = { 0 };
    UINT uSnedCount = 0;
    DWORD dwFlag = 0;

    if (bExtended) dwFlag |= KEYEVENTF_EXTENDEDKEY;
    if (bScan) dwFlag |= KEYEVENTF_SCANCODE;

    if (bDown)
    {
        inputs[uSnedCount].type = INPUT_KEYBOARD;
        inputs[uSnedCount].ki.wVk = wVk;
        inputs[uSnedCount].ki.wScan = wScan;
        inputs[uSnedCount].ki.dwFlags = dwFlag;
        uSnedCount++;
    }

    if (bUp)
    {
        inputs[uSnedCount].type = INPUT_KEYBOARD;
        inputs[uSnedCount].ki.wVk = wVk;
        inputs[uSnedCount].ki.wScan = wScan;
        inputs[uSnedCount].ki.dwFlags = dwFlag | KEYEVENTF_KEYUP;
        uSnedCount++;
    }

    UINT uCount = ::SendInput(uSnedCount, inputs, sizeof(INPUT));

    return uSnedCount == uCount;
}

bool CInputUtils::Keyboard(_tstring strKey, bool bDown/* = true*/, bool bUp/* = true*/)
{
    bool bFind = false;
    KBDATA_INFO keyData;

    for (const auto& item : m_KeyMap)
    {
        if (0 == _tcsicmp(item.first.c_str(), strKey.c_str()))
        {
            keyData = item.second;
            bFind = true;
        }
    }

    if (!bFind)
    {
        return false;
    }

    INPUT inputs[0x02] = { 0 };
    UINT uSnedCount = 0;

    if (bDown)
    {
        inputs[uSnedCount].type = INPUT_KEYBOARD;
        inputs[uSnedCount].ki.wVk = keyData.vkCode;
        inputs[uSnedCount].ki.wScan = keyData.scanCode;
        inputs[uSnedCount].ki.dwFlags = keyData.flags;
        uSnedCount++;
    }

    if (bUp)
    {
        inputs[uSnedCount].type = INPUT_KEYBOARD;
        inputs[uSnedCount].ki.wVk = keyData.vkCode;
        inputs[uSnedCount].ki.wScan = keyData.scanCode;
        inputs[uSnedCount].ki.dwFlags = keyData.flags | KEYEVENTF_KEYUP;
        uSnedCount++;
    }

   UINT uCount = ::SendInput(uSnedCount, inputs, sizeof(INPUT));

    return uSnedCount == uCount;
}

bool CInputUtils::KeyboardChar(TCHAR ch)
{
    INPUT inputs[0x01] = { 0 };

    inputs[0].type = INPUT_KEYBOARD;
    inputs[0].ki.wVk = 0;
    inputs[0].ki.wScan = ch;
    inputs[0].ki.dwFlags = KEYEVENTF_UNICODE;

    UINT uCount = ::SendInput(1, inputs, sizeof(INPUT));

    return 1 == uCount;
}

bool CInputUtils::KeyboardText(_tstring strText)
{
    INPUT inputs[0x01] = { 0 };
    inputs[0].type = INPUT_KEYBOARD;
    inputs[0].ki.wVk = 0;
    inputs[0].ki.dwFlags = KEYEVENTF_UNICODE;
    UINT uCount = 0;

    for (const auto& item : strText)
    {
        inputs[0].ki.wScan = item;
        uCount = ::SendInput(1, inputs, sizeof(INPUT));
    }

    return 1 == uCount;
}

bool CInputUtils::MouseMove(LONG x, LONG y, bool bAbsolute)
{
    LONG dwWidth = ::GetSystemMetrics(SM_CXSCREEN);
    LONG dwHeight = ::GetSystemMetrics(SM_CYSCREEN);

    INPUT inputs[0x01] = { 0 };
    inputs[0].type = INPUT_MOUSE;

    if (bAbsolute)
    {
        inputs[0].mi.dx = (LONG)((double)65535 / (double)dwWidth * x);
        inputs[0].mi.dy = (LONG)((double)65535 / (double)dwHeight * y);
    }
    else
    {
        inputs[0].mi.dx = x;
        inputs[0].mi.dy = y;
    }

    inputs[0].mi.dwFlags = MOUSEEVENTF_MOVE;
    if (bAbsolute)
    {
        inputs[0].mi.dwFlags |= MOUSEEVENTF_ABSOLUTE;
    }

    UINT uCount = ::SendInput(1, inputs, sizeof(INPUT));

    return 1 == uCount;
}

bool CInputUtils::MouseKey(bool bLeft, bool bRight, bool bMiddle, bool bDown/* = true*/, bool bUp/* = true*/)
{
    INPUT inputs[0x06] = { 0 };
    UINT uSendCount = 0;

    if (bLeft)
    {
        if (bDown)
        {
            inputs[uSendCount].type = INPUT_MOUSE;
            inputs[uSendCount].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
            uSendCount++;
        }

        if (bUp)
        {
            inputs[uSendCount].type = INPUT_MOUSE;
            inputs[uSendCount].mi.dwFlags = MOUSEEVENTF_LEFTUP;
            uSendCount++;
        }
    }

    if (bRight)
    {
        if (bDown)
        {
            inputs[uSendCount].type = INPUT_MOUSE;
            inputs[uSendCount].mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;
            uSendCount++;
        }

        if (bUp)
        {
            inputs[uSendCount].type = INPUT_MOUSE;
            inputs[uSendCount].mi.dwFlags = MOUSEEVENTF_RIGHTUP;
            uSendCount++;
        }
    }

    if (bMiddle)
    {
        if (bDown)
        {
            inputs[uSendCount].type = INPUT_MOUSE;
            inputs[uSendCount].mi.dwFlags = MOUSEEVENTF_MIDDLEDOWN;
            uSendCount++;
        }

        if (bUp)
        {
            inputs[uSendCount].type = INPUT_MOUSE;
            inputs[uSendCount].mi.dwFlags = MOUSEEVENTF_MIDDLEUP;
            uSendCount++;
        }
    }

    UINT uCount = ::SendInput(uSendCount, inputs, sizeof(INPUT));

    return uSendCount == uCount;
}

bool CInputUtils::MouseWheelForward(LONG nSpeed/* = 1*/)
{
    INPUT inputs[0x01] = { 0 };

    inputs[0].type = INPUT_MOUSE;
    inputs[0].mi.dwFlags = MOUSEEVENTF_WHEEL;
    inputs[0].mi.mouseData = WHEEL_DELTA * nSpeed;

    UINT uCount = ::SendInput(1, inputs, sizeof(INPUT));

    return 1 == uCount;
}

bool CInputUtils::MouseWheelBackward(LONG nSpeed/* = 1*/)
{
    INPUT inputs[0x01] = { 0 };

    inputs[0].type = INPUT_MOUSE;
    inputs[0].mi.dwFlags = MOUSEEVENTF_WHEEL;
    inputs[0].mi.mouseData = 0 - (WHEEL_DELTA * nSpeed);

    UINT uCount = ::SendInput(1, inputs, sizeof(INPUT));

    return 1 == uCount;
}

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值