2016-07-27 29 views
0

我想使用SendInput()函数来自动按下一些按键。为什么不是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; 
} 

我启动该程序,然后输入一个字符串,只为没有发生。它出了什么问题?

+1

检查从sendinput返回代码和调用GetLastError。 –

+0

什么应用程序应该接收此输入?研究UIPI。 –

+0

@RemyLebeau“这个函数在被UIPI阻塞时失败。请注意,GetLastError和返回值都不能表明失败是由UIPI阻塞引起的。” [每发送输入函数的msdn描述](https://msdn.microsoft.com/en-us/library/windows/desktop/ms646310(v = vs.85).aspx) –

回答

0

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

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

你还必须检查关键状态的锁定和移位等。以这种方式使用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)); 
    } 
} 
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; 
}