[转]keybd_event 被 SendInput 替代

在开发的长河中大家连年会遇到多表操作的急需,昨日自我享受一个关于查询的办法,

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

序言:在利用NHibernate中,需求将用户表(Users)、部门表(Departments),链表查询,在网上找了诸多资料,可以在布局文件中布局相应的性质达到关联的法力,一对多、多对一、多对多的办法,可是使用后发现有点困难,尤其时刚伊始接触NHibernate,有点儿难驾驭,现在自己使用一种新的法门,使用大家最熟习的SQL来成功有关职能

 keybd_event
  函数成效:该函数合成三次击键事件。系统可应用那种合成的击键事件来暴发WM_KEYUP或WM_KEYDOWN信息,键盘驱动程序的暂停处理程序调用keybd_event函数。在Windows
NT中该函数己被使用SendInput来替代它。

 

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

1.0 首先大家必要把条件布署好,请参考我眼前的随笔,

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

2.0 大家在NHibernate萨姆ple中定义一个方法

SendInput模拟键盘输入的难点

葡京网上娱乐场 1葡京网上娱乐场 2

日前接触到那么些函数,由此精通了弹指间,总括一下列在那。

/// <summary>
        /// 查询所有数据
        /// </summary>
        /// <returns></returns>
        public IList<Object> GetCustomers()
        {
            return Session.CreateSQLQuery("select  A.*,B.* from Users A ,Departments B WHERE A.Dept_id = B.dept_id")
                .AddEntity(typeof(Users)).AddEntity(typeof(Departments)).List<Object>();

            //return Session.QueryOver<MyDepartments>().List();
        }

自我通晓它的视角是如何通过它向移动窗口输入字符,那是成百上千先后都有的效益(我猜Visual
Assist X就用了这么些功用)。

询问形式

依照MSDN,此函数模拟按键操作,将有些音讯插入键盘或鼠标的输入流中,Windows对它举办拍卖,生成对应的WM_KEYDOWN或WM_KEYUP事件,那一个事件与常见键盘输入一起进去应用程序的音讯循环,它们不仅能够转移为WM_CHAR音讯,还足以转移为别的(诸如加快键)等音信。

  

应用它来发送字符音信,并从未看起来那么简单。那有五个须求考虑的标题:

  正如上图所属我们利用了连表查询,
这几个时候查询出来的结果是两张表的国有交集
包涵所有的字段,随后大家在末端使用.AddEntity(typeof(Users)),NHibernateSample会在编译的时候取得大家传入的类型,随即找到相应的布局文件,根据部署文件相应的布署,就可以将我们的类中的字段和数据库查询结果的字段一一对应
,然后生成对应的结果集,最终大家输出.List<Object>();
那样就得到了连表查询的结果,那么我们该怎样使用它呢?重回出来的结果集又是如何体统的啊?

1.
输入法的转换。例如要求向活动窗口发送一些英文字符,我们恐怕想象那样来落到实处:获取对应键盘字符的虚拟键码,发送一个SendInput。不过假诺移动窗口正在选取一个输入法,那么大家发送出去的信息,会进入输入法的Composition窗口,最后被更换为象形文字或被撇下。唯有当输入法关闭时,程序运行的成效才会像大家希望的那么,在运动窗口中显得出英文字符。

 葡京网上娱乐场 3

2.
对此华语字符,应该怎么发送给活动窗口?由于SendInput模拟的是WM_KEYDOWN和WM_KEYUP事件,依照一般的思绪,我们是或不是应当得到普通话字符的输入法编码(拼音或五笔码),然后向移动窗口发送编码相关的SendInput?那这不单必要活动窗口打开输入法,甚至还要获知它的编码形式。

 

总的看,若平素如想象中那样采纳SendInput来输入字符,则必须分析活动窗口的输入法情形。而且输入英文时,须求关闭输入法,输入汉语时,又需要打开输入法。若真要以这样的思路来促成,则肯定是为难成功的。

回到出来的结果集的规范:NHibernateSample将数据库中的一行数据对应到大家加以的实体类对象,因而集合中每一个目的又含有三个目标一个是部门属性/值的见面,另一个是用户属性/值的会聚 

那就是说,有没有不依靠活动窗口输入法意况的措施呢?

葡京网上娱乐场 4

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

 

MSDN对此方法的表明为:INPUT_KEYBOARD接济非键盘的输入方式,例如手写识别或语音识别,通过KEYEVENTF_UNICODE标识,那些主意与键盘(文本)输入别无二致。假如指定了KEYEVENTF_UNICODE,SendInput发送一个WM_KEYDOWN或WM_KEYUP音信给移动窗口的线程新闻队列,信息的wParam参数为VK_PACKET。GetMessage或PeedMessage一旦得到此音讯,就把它传递给TranslateMessage,TranslateMessage根据wScan中指定的Unicode字符暴发一个WM_CHAR信息。若窗口是ANSI窗口,则Unicode字符会自动转换为相应的ANSI字符。

该怎么使用它
:手动的拼装重返的结果集

其余索要向运动窗口输入字符(包涵英文)的效果均应选取那种措施来贯彻。事实上,键盘新闻转换为字符信息的历程是很复杂的,这或许与键盘布局、区域、换档状态等重重元素有关,那也是Windows要运用TranslateMessage来转换音讯的原因。因而,不应该计算通过击键事件来企图向活动窗口输入特定的字符。

葡京网上娱乐场 5葡京网上娱乐场 6

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

//创建一个操作类对象  这里还记得嘛?我们在NHibernateSample操作类的构造函数中声明了一个ISession的参数 这里我们调用帮助类的GetSession()方法返回一个ISession
            NHibernateSample _sample = new NHibernateSample(new NHibernateHelper().GetSession());


            //声明一个对象的集合  由于是多对一的关系 所以我在用户类中自定义了一个部门类型的属性字段
            List<Users> list_u = new List<Users>();

            //存放数据库返回的查询结果
            IList<Object> list_o = _sample.GetCustomers();

            //这里因为返回的是Object类型 所以只能用for循环 不能使用foreach
            for (int i = 0; i < list_o.Count; i++)
            {
                //获取集合中的对象
                Object[] isu_d = (Object[])_sample.GetCustomers()[i];

                //将当前对象中的第一个用户属性/值的对象集合插入到U对象中
                Users u = (Users)isu_d[0];

                //将当前对象中的第二个部门属性/值的对象集合插入到U对象的Departments(相应的部门类型属性 上面提到过的)中
                u.Departments = (Departments)isu_d[1];
                //添加到集合中
                list_u.Add(u);
            }
            //最后返回的就是 用户的集合list_u  在用户中的属性Departments包含了相对应的部门信息
            list_u.Count();

1.
没有为KEYBDINPUT.dwFlags指定KEYEVENTF_KEYUP标识时,SendInput将生成WM_KEYDOWN消息,否则生成WM_KEYUP新闻,由于唯有WM_KEYDOWN会转换为字符消息,由此,若以输入字符为目的,则不应指定KEYEVENTF_KEYUP标识。

拔取重回的结果集

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));

有关第二点内容,我很有疑问。因为事先有人在网上帖的代码是联合发送的,想必有人这样做过同时成功了。我不理解是不是与系统或任何因素有关。我也曾打算尝试解决此题材,但并未得逞:

1.
依据MSDN,KEYBDINPUT.time是一个年华戳,假使为零,系统将选择它自己的时日戳。由此我难以置信八个一起发送的事件,是还是不是因为其时间戳相同,而被忽视掉了。于是自己在上述代码中显式设置了该属性,再统一发送,结果仍旧是没有暴发其余信息。

2.
自家分别品尝了三种情形:合并发送的两条音讯都尚未点名KEYEVENTF_KEYUP(期望得到八个相同的字符输入);合并发送的两条新闻具有差距的虚拟键码且都不指定KEYEVENTF_KEYUP(期望得到八个例外的字符输入)。结果如故仍然战败,没有生出其余音信。

自己不知情那是还是不是意味:对于键盘输入,不容许将音讯合并发送。

若您明白其中原因或测试到与我差其余场景,请与我联系:yedaoq@126.com

有关知识:

1.
输入法也得以拍卖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) );