C++[转]keybd_event 被 SendInput 替代

 http://baike.baidu.com/view/1080077.htm

 keybd_event
  函数功效:该函数合成三反击键事件。系统可利用这种合成的击键事件来产生WM_KEYUP或WM_KEYDOWN音信,键盘驱动程序的中止处理程序调用keybd_event函数。在Windows
NT中该函数己被使用SendInput来取代它。

————————————————– 

http://www.cnblogs.com/yedaoq/archive/2010/12/30/1922305.html

SendInput模拟键盘输入的难点

近年触及到这一个函数,因而精通了须臾间,总括一下列在那。

自个儿打听它的着眼点是怎么通过它向运动窗口输入字符,那是多多益善主次都有的效益(小编猜Visual
Assist X就用了这些效应)。

传说MSDN,此函数模拟按键操作,将部分消息插入键盘或鼠标的输入流中,Windows对它进行拍卖,生成对应的WM_KEYDOWN或WM_KEYUP事件,那么些事件与普通键盘输入壹起进去应用程序的音讯循环,它们不但能够转移为WM_CHATiggo音讯,还足以转移为别的(诸如加快键)等消息。

应用它来发送字符音讯,并未看起来那么不难。那有三个供给考虑的标题:

1.
输入法的变换。例如供给向活动窗口发送1些英文字符,大家大概想象那样来落到实处:获取对应键盘字符的虚拟键码,发送二个SendInput。不过只要移动窗口正在选用一个输入法,那么大家发送出去的消息,会进去输入法的Composition窗口,最后被转移为象形文字或被扬弃。唯有当输入法关闭时,程序运营的效力才会像大家期待的那么,在移动窗口中呈现出英文字符。

二.
对此华语字符,应该怎么发送给活动窗口?由于SendInput模拟的是WM_KEYDOWN和WM_KEYUP事件,依照1般的思绪,大家是还是不是相应赢得普通话字符的输入法编码(拼音或伍笔码),然后向活动窗口发送编码相关的SendInput?那这不光须要活动窗口打开输入法,甚至还要获知它的编码情势。

因此看来,若直接如想象中那样选用SendInput来输入字符,则必须分析活动窗口的输入法景况。而且输入英文时,供给关闭输入法,输入普通话时,又供给打开输入法。若真要以那样的笔触来贯彻,则早晚是麻烦成功的。

那么,有未有不依靠活动窗口输入法情况的主意呢?

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

MSDN对此方法的表明为:INPUT_KEYBOA君越D扶助非键盘的输入格局,例如手写识别或语音识别,通过KEYEVENTF_UNICODE标识,这一个措施与键盘(文本)输入别无二致。要是钦赐了KEYEVENTF_UNICODE,SendInput发送三个WM_KEYDOWN或WM_KEYUP新闻给移动窗口的线程新闻队列,新闻的wParam参数为VK_PACKET。GetMessage或PeedMessage1旦获得此新闻,就把它传递给TranslateMessage,TranslateMessage依据wScan中钦点的Unicode字符发生1个WM_CHA帕杰罗新闻。若窗口是ANSI窗口,则Unicode字符会自动转换为对应的ANSI字符。

其它索要向运动窗口输入字符(包罗英文)的作用均应使用那种方法来实现。事实上,键盘音讯转换为字符音信的进程是很复杂的,那恐怕与键盘布局、区域、换档状态等诸多成分有关,那也是Windows要使用TranslateMessage来转换新闻的来由。由此,不该总括透过击键事件来企图向活动窗口输入特定的字符。

经测试,SendInput还有七个值得注意的地点:

1.
没有为KEYBDINPUT.dwFlags指定KEYEVENTF_C++,KEYUP标识时,SendInput将生成WM_KEYDOWN新闻,不然生成WM_KEYUP新闻,由于唯有WM_KEYDOWN会转换为字符消息,因而,若以输入字符为指标,则不应钦命KEYEVENTF_KEYUP标识。

二.
倘诺大家想达到实际做2遍击键所爆发的功效:顺序产生2个WM_KEYDOWN和一个WM_KEYUP事件。则必须分别以不点名KEYEVENTF_KEYUP和指定KEYEVENTF_KEYUP的措施实施叁次SendInput操作。SendInput允许在三遍调用中发送多少个模拟消息:

INPUT input[2];
memset(input, 0, 2 * 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));

但事实上,那将造成不发生别的音信。那七个音讯必须分离发送,如下所示:

INPUT input[2];
memset(input, 0, 2 * sizeof(INPUT));

input[0].type = INPUT_KEYBOARD;
input[0].ki.wVk = data;
SendInput(1, input, sizeof(INPUT));

input[1].type = INPUT_KEYBOARD;
input[1].ki.wVk = data;
input[1].ki.dwFlags = KEYEVENTF_KEYUP;

SendInput(1, input + 1, sizeof(INPUT));

关于第一点内容,笔者很有疑难。因为事先有人在网上帖的代码是联合发送的,想必有人如此做过同时成功了。笔者不驾驭是还是不是与系统或其余因素有关。笔者也曾试图尝试解决此题材,但未曾马到功成:

一.
依照MSDN,KEYBDINPUT.time是贰个时日戳,要是为零,系统将运用它本身的岁月戳。由此作者质疑三个同步发送的轩然大波,是否因为其时间戳相同,而被忽视掉了。于是自个儿在上述代码中显式设置了该属性,再统一发送,结果依然是一直不发出任何音信。

二.
小编分别品尝了三种情景:合并发送的两条新闻都并未点名KEYEVENTF_KEYUP(期望获取八个1律的字符输入);合并发送的两条音讯具有分歧的虚构键码且都不钦定KEYEVENTF_KEYUP(期望获得三个不等的字符输入)。结果依然战败,未有发生任何音信。

笔者不明了那是还是不是意味着:对于键盘输入,不允许将音信合并发送。

若你通晓个中原因或测试到与自家差异的情景,请与本人交换:yedaoq@126.com

相关知识:

壹.
输入法也得以处理SendInput发送的Unicode音信,具体方法不详。见MSDN中ImmGetProperty方法的参考:当dwIndex参数为IGP_PROPERTY时,IME_PROP_ACCEPT_WIDE_VKEY是一个也许的再次回到值,它表示IME会处理SendInput函数以VK_PACKET注入的Unicode字符,若再次回到值无该标识,则Unicode字符会直接发送给应用程序。 


http://xylvhp.blog.163.com/blog/static/31123614201101104644542/

在VC中动用SendInput函数落成汉语的全自动输入(ZZ)

2011-01-11 12:46:44| 分类: C++
|字号
订阅

率先是,头文件必须包罗以下三个:
#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”);
}
}

//////////////////////////////////////////////////////////////////////////////////////////////////////

SendInput模拟键盘和鼠标事件

INPUT kbinput[5];
ZeroMemory( &kbinput, sizeof(INPUT)*5 );

kbinput[0].type = INPUT_KEYBOARD;
kbinput[0].ki.wVk = ‘Z’;

kbinput[1].type = INPUT_KEYBOARD;
kbinput[1].ki.wVk = ‘W’;

kbinput[2].type = INPUT_KEYBOARD;
kbinput[2].ki.wVk = ‘J’;
//kbinput[2].ki.dwFlags = KEYEVENTF_KEYUP;

kbinput[3].type=INPUT_MOUSE;
kbinput[3].mi.dx=100;
kbinput[3].mi.dy=100;
kbinput[3].mi.mouseData=0;
kbinput[3].mi.dwFlags=MOUSEEVENTF_RIGHTDOWN;

kbinput[4].type=INPUT_MOUSE;
kbinput[4].mi.dx=100;
kbinput[4].mi.dy=100;
kbinput[4].mi.mouseData=0;
kbinput[4].mi.dwFlags=MOUSEEVENTF_RIGHTUP;

UINT uRet = SendInput( 5, kbinput, sizeof(INPUT) );