最近闲着没事,就随意浏览博客,突然发现了一种模拟键盘输入的办法(之前一直想破脑袋的都没有想到的),然后借此机会说明一下。
具体实现方法
1)借用粘贴板
这是比较容易想到的,也最受程序员鄙视的一种办法,如果你实在想不到好的办法,用这种方法救救急还是可以的,具体代码可以参照MSDN。(当然,此法有一个好处,不用处理英文和中文的区别,直接无脑复制过去即可)
2)利用SendInput来模拟
这种就是模拟输入法输入的过程,需要处理中文编码的问题(本人对于编码不是太在行,所以就不多做解释了,直接看代码吧)
#include <iostream>
#include <windows.h>
#include <string>
using namespace std;
std::wstring stringToWstring(const std::string& str)
{
LPCSTR pszSrc = str.c_str();
int nLen = MultiByteToWideChar(CP_ACP, 0, pszSrc, -1, NULL, 0);
if (nLen == 0)
return std::wstring(L"");
wchar_t* pwszDst = new wchar_t[nLen];
if (!pwszDst)
return std::wstring(L"");
MultiByteToWideChar(CP_ACP, 0, pszSrc, -1, pwszDst, nLen);
std::wstring wstr(pwszDst);
delete[] pwszDst;
pwszDst = NULL;
return wstr;
}
void SendAscii(wchar_t data, BOOL shift)
{
INPUT input[2];
memset(input, 0, 2 * sizeof(INPUT));
if (shift)
{
input[0].type = INPUT_KEYBOARD;
input[0].ki.wVk = VK_SHIFT;
SendInput(1, input, sizeof(INPUT));
}
input[0].type = INPUT_KEYBOARD;
input[0].ki.wVk = data;
input[1].type = INPUT_KEYBOARD;
input[1].ki.wVk = data;
input[1].ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(2, input, sizeof(INPUT));
if (shift)
{
input[0].type = INPUT_KEYBOARD;
input[0].ki.wVk = VK_SHIFT;
input[0].ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, input, sizeof(INPUT));
}
}
void SendUnicode(wchar_t data)
{
INPUT input[2];
memset(input, 0, 2 * sizeof(INPUT));
input[0].type = INPUT_KEYBOARD;
input[0].ki.wVk = 0;
input[0].ki.wScan = data;
input[0].ki.dwFlags = 0x4;//KEYEVENTF_UNICODE;
SendInput(1, &input[0], sizeof(INPUT));
input[1].type = INPUT_KEYBOARD;
input[1].ki.wVk = 0;
input[1].ki.wScan = data;
input[1].ki.dwFlags = KEYEVENTF_KEYUP | 0x4;//KEYEVENTF_UNICODE; 这里是为了防止英文字符进入到系统输入法里面,则可以解决国内的输入法软件拦截的问题,但是国外的软件一般做了UNICODE兼容,所以还是会有问题。
SendInput(1, &input[1], sizeof(INPUT));
}
void SendKeys(string msg)
{
short vk;
BOOL shift;
wstring data = stringToWstring(msg);
int len = data.size();
for (int i = 0; i<len; i++)
{
if (data[i] >= 0 && data[i]<256) //ascii字符
{
vk = VkKeyScanW(data[i]);
if (vk == -1)
{
SendUnicode(data[i]);
}
else
{
if (vk < 0)
{
vk = ~vk + 0x1;
}
shift = vk >> 8 & 0x1;
if (GetKeyState(VK_CAPITAL) & 0x1)
{
if (data[i] >= 'a' && data[i] <= 'z' || data[i] >= 'A' && data[i] <= 'Z')
{
shift = !shift;
}
}
SendAscii(vk & 0xFF, shift);
}
}
else //unicode字符
{
SendUnicode(data[i]);
}
}
}
void main()
{
Sleep(5000);
//如果你是在UTF8的环境下使用,字符串要转成GBK格式的,否则必乱码
SendKeys("我爱北京天安门");
}
//这里只是先说一下sendinput的作用,至于处理的步骤,就不说了,我也不大懂。
//还有一点。某些输入法会拦截sendinput,然后就变成了输入法弹出一个候选词条框,
3)借用keybd_event 据说已经不用了
这玩意只能处理英文,不能处理中文,但是博主在测试过程中没有发现输入法会拦截英文字符的现象,可以考虑和上面的那个函数合并。
void SendAscii(wchar_t data, BOOL shift)
{
if (shift)
{
keybd_event(VK_SHIFT, 0, 0, 0);
}
keybd_event(data, 0, 0, 0);
keybd_event(data, 0, KEYEVENTF_KEYUP, 0);
if (shift)
{
keybd_event(VK_SHIFT, 0, 0, 0);
}
}
//理论上来说,这里应该也会拦截,keybd_event的下层还是用sendinput实现的,可能博主的环境有点不一样吧,详细的还需要自己测试一下。