您的位置:首页 > 编程语言 > C语言/C++

C++学习笔记之SendInput()模拟键盘输入的问题

2017-10-15 17:15 579 查看

写在前面

本人刚入C++开发,有很多也是不懂。在网上找了一个模拟键盘输入的代码,结果输入中文没问题,输入英文却导致字符被中文输入法的框给截了,加上翻墙软件貌似又被截了一大波,真尼玛日了天美了。

正文部分

正确的做法就是将字符转换为UNICODE编码即可。

以下来自于某博客的摘抄:

那么,有没有不依赖活动窗口输入法状态的方式呢?

其实是有的,使用SendInput模拟键盘输入时,其参数是KEYBDINPUT结构,通过将其dwFlags成员设置KEYEVENTF_UNICODE就可以了。使用此方式,只需将KEYBDINPUT.wScan设置为字符的Unicode编码即可。对于英文字符,不需要关闭活动窗口的输入法;对于中文字符,也不要求活动窗口打开输入法和将字符转换为输入法编码。

相关代码看这里:

INPUT input[2];
20             memset(input, 0, sizeof(input));
21             //按下 向下方向键
22             input[0].ki.wVk = keyvalue;
23             input[0].type = INPUT_KEYBOARD;
24             //松开 向下方向键
25             input[1].ki.wVk = data; //你的字符
26             input[1].type = INPUT_KEYBOARD;
27             input[1].ki.dwFlags = KEYEVENTF_KEYUP;
28             //该函数合成键盘事件和鼠标事件,用来模拟鼠标或者键盘操作。事件将被插入在鼠标或者键盘处理队列里面
29             SendInput(2, input, sizeof(INPUT));


完整程序:

首先是,头文件必须包含以下两个:
#include <winable.h>
#include <atlconv.h>
前者是SendInput函数要用到,后者是字符串转换的时候要用到。

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;

input[1].type = INPUT_KEYBOARD;
input[1].ki.wVk = 0;
input[1].ki.wScan = data;
input[1].ki.dwFlags = KEYEVENTF_KEYUP | 0x4;//KEYEVENTF_UNICODE;

SendInput(2, input, sizeof(INPUT));
}
//为方便使用,下面这个函数包装了前两个函数。

void SendKeys(CString msg)
{
short vk;
BOOL shift;
USES_CONVERSION;
wchar_t* data = T2W(msg.GetBuffer(0));
int len = wcslen(data);
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]);
}
}
}
直接调用SendKeys函数就可以在当前光标的位置自动输入指定的字符串,下面的例子演示了如何自动打开记事本程序并输入一段话:
void CSendInputDlg::OnTest()
{
ShellExecute(NULL, NULL, "notepad.exe", NULL, NULL, SW_SHOWNORMAL);

Sleep(500); //为了确保记事本程序打开完毕,稍等片刻
CWnd *pWnd = FindWindow(NULL, "无标题 - 记事本");
if (pWnd)
{
pWnd->SetForegroundWindow();
SendKeys("我是sway,我爱中国!\nI love China!\nEmail: xmujava@163.com\t\n2010-05-21  \b\b");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息