为什么SendInput()不工作?

时间:2016-07-27 20:26:17

标签: c++ bots

我想使用SendInput()函数自动按某些键。

我的代码:

#include "stdafx.h"
#include <iostream>
#include <string>
#include <Windows.h>

using std::cin;
using std::cout;
using std::string;

void presskeys(string s){
    INPUT ip;
    ip.ki.wScan = 0;
    ip.ki.time = 0;
    ip.ki.dwExtraInfo = 0;
    HKL kbl = GetKeyboardLayout(0);
    for (unsigned int i = 0; i < s.length(); ++i) {
        ip.type = INPUT_KEYBOARD;
        char c = s[i];
        int vk = VkKeyScanEx((WCHAR)c, kbl);
        ip.ki.wVk = vk;
        SendInput(1, &ip, sizeof(ip));
        ip.ki.dwFlags = KEYEVENTF_KEYUP;
        SendInput(1, &ip, sizeof(ip));
    }
}
int main()
{
    cout << "Enter a string!\n";
    string str;
    cin >> str;
    Sleep(5000);
    presskeys(str);
    cout << "Done!\n";
    return 0;
}

我启动程序并输入一个字符串,但不会发生任何事情。它出了什么问题?

2 个答案:

答案 0 :(得分:2)

与Barmak说的一样,您正在以不正确的方式将ANSI和UNICODE混合在一起,并且您没有正确管理输入标志。

发送字符串字符时,最好通过KEYEVENTF_UNICODE标志发送UTF-16代码单元,而不是使用扫描代码或虚拟密钥。

您还应该为整个字符串调用SendInput() 一次,其中包含多个INPUT结构,以便所有字符作为一个单元一起发送,而不是被用户或其他应用程序/线程同时生成的其他输入事件中断或混合。

请参阅my answerSending Two or more chars using SendInput

例如:

#include "stdafx.h"
#include <Windows.h>

#include <iostream>
#include <string>
#include <vector>

void presskeys(const std::wstring &str)
{
    int len = str.length();
    if (len == 0) return;

    std::vector<INPUT> in(len*2);
    ZeroMemory(&in[0], in.size()*sizeof(INPUT));

    int i = 0, idx = 0;
    while (i < len)
    {
        WORD ch = (WORD) str[i++];

        if ((ch < 0xD800) || (ch > 0xDFFF))
        {
            in[idx].type = INPUT_KEYBOARD;
            in[idx].ki.wScan = ch;
            in[idx].ki.dwFlags = KEYEVENTF_UNICODE;
            ++idx;

            in[idx] = in[idx-1];
            in[idx].ki.dwFlags |= KEYEVENTF_KEYUP;
            ++idx;
        }
        else
        {
            in[idx].type = INPUT_KEYBOARD;
            in[idx].ki.wScan = ch;
            in[idx].ki.dwFlags = KEYEVENTF_UNICODE;
            ++idx;

            in[idx].type = INPUT_KEYBOARD;
            in[idx].ki.wScan = (WORD) str[i++];
            in[idx].ki.dwFlags = KEYEVENTF_UNICODE;
            ++idx;

            in[idx] = in[idx-2];
            in[idx].ki.dwFlags |= KEYEVENTF_KEYUP;
            ++idx;

            in[idx] = in[idx-2];
            in[idx].ki.dwFlags |= KEYEVENTF_KEYUP;
            ++idx;
        }
    }

    SendInput(in.size(), &in[0], sizeof(INPUT));
}

int main()
{
    std::wcout << L"Enter a string and press enter:\n";
    std::wstring str;
    if (std::getline(std::wcin, str))
    {
        presskeys(str);
        std::wcout << L"Done!\n";
    }
    return 0;
}

答案 1 :(得分:0)

您正在使用ANSI字符串,因此请使用VkKeyScanExA,或切换到std::wstring。但是不要将ANSI与UNICODE混合使用,也不要使用强制转换来隐藏编译器警告。

您必须将ip.ki.dwFlags重置为零以指示按键关闭。然后将其设置为KEYEVENTF_KEYUP

你还必须检查caplock和shift等的关键状态。以这种方式使用SendInput是没有意义的,第一个参数是允许一次发送多个输入。您也可以使用keybd_event

void presskeys(string s) 
{
    INPUT ip;
    ip.type = INPUT_KEYBOARD;
    ip.ki.wScan = 0;
    ip.ki.time = 0;
    ip.ki.dwExtraInfo = 0;
    HKL kbl = GetKeyboardLayout(0);
    for (unsigned int i = 0; i < s.length(); ++i) 
    {
        char c = s[i];
        ip.ki.wVk = VkKeyScanExA(c, kbl); //<== don't mix ANSI with UNICODE
        ip.ki.dwFlags = 0; //<= Add this to indicate key-down
        SendInput(1, &ip, sizeof(ip));
        ip.ki.dwFlags = KEYEVENTF_KEYUP;
        SendInput(1, &ip, sizeof(ip));
    }
}