Win下模拟键盘输入的三种办法

最近闲着没事,就随意浏览博客,突然发现了一种模拟键盘输入的办法(之前一直想破脑袋的都没有想到的),然后借此机会说明一下。

具体实现方法

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实现的,可能博主的环境有点不一样吧,详细的还需要自己测试一下。
原创文章 19 获赞 1 访问量 434

猜你喜欢

转载自blog.csdn.net/weixin_45718152/article/details/105612524