问题: 如何使用 SendMessage 发送按键 Alt+A ( 积分: 50 ) <br>分类: Windows API <br> <br>来自: xuhao1, 时间: 2004-08-07 15:07:00, ID: 2753402 <br>如何使用 SendMessage 发送按键 Alt+A <br> <br>来自: 刘麻子, 时间: 2004-08-07 15:11:54, ID: 2753417 <br>先发 alt 按下 , 再发 a 按下 , 再发 a 抬起 , 再发 alt 抬起 ... <br> <br>来自: xuhao1, 时间: 2004-08-07 15:21:34, ID: 2753433 <br>试过,不行 <br> <br>来自: wen00000000, 时间: 2004-08-07 15:32:29, ID: 2753445 <br>keybd_event(...) <br>keybd_event(...) <br>keybd_event(...) <br>keybd_event(...) <br> <br>来自: 风铃夜思雨, 时间: 2004-08-07 19:09:00, ID: 2753720 <br>keybd_event(17,mapvirtualkey(17,0),0,0); <br>keybd_event(65,mapvirtualkey(65,0),0,0); <br>keybd_event(65,mapvirtualkey(65,0),keyeventf_keyup,0); <br>keybd_event(17,mapvirtualkey(17,0),keyeventf_keyup,0); <br> <br>来自: xuhao1, 时间: 2004-08-07 22:37:05, ID: 2753886 <br>使用 SendMessage <br> <br>来自: 刘麻子, 时间: 2004-08-11 11:23:57, ID: 2759060 <br> SendMessage(Handle, WM_SYSCHAR, ORD('A'), $201E0001); <br> <br>来自: 刘麻子, 时间: 2004-08-11 12:05:29, ID: 2759108 <br> 关于按键类消息 主要有这么几个 : <br><br>WM_KEYDOWN,WM_KEYUP,WM_CHAR;WM_SYSKEYDOWN,WM_SYSKEYUP,WM_SYSCHAR 。。 <br><br>其中带Down Up 的是虚拟键消息 在我们键盘上按下、抬起 的时候 被放到消息队列 <br>之后 Down 被程序消息循环取出来 执行:TranslateMessage(Msg); 转成对应的带CHAR的消息 <br><br>所以Down UP ,不能用Sendmessage而要用PostMessage,而CHAR可以直接SendMessage. <br>在这里 您要求的是Alt+A,当按下一个键时alt同时被按下,则触发WM_SYSKEY系列消息, <br>而不是 WM_KEY ,这里我直接SendMessage了一个 WM_SYSKEYCHAR ,就可以了。 <br><br>其实 也可以PostMessage WM_SYSKEYDOWN 和 WM_SYSKEYUP , 会自动转成WM_SYSKEYCHAR。 <br> 比如: <br> PostMessage(Handle, WM_SYSKEYDOWN, ORD('A'), $201E0001); <br> PostMessage(Handle, WM_SYSKEYUP, ORD('A'), $C01E0001 ); <br><br>但是如果这里用SendMessage就不行 , 因为没有经过消息队列。 <br>而TranslateMessage一般都是消息循环中调用的(不断从消息队列中取消息并分发) <br> <br>来自: 刘麻子, 时间: 2004-08-11 12:04:20, ID: 2759172 <br> 再举个例子 比如我要给 edit 一个字符 , 有几种方法 : <br><br> PostMessage(Edit1.Handle, WM_KEYDOWN, ORD('A'), $001E0001); <br> PostMessage(Edit1.Handle, WM_KEYUP, ORD('A'), $C01E0001 ); <br>-------------------------------- <br> SendMessage(Edit1.Handle, WM_CHAR, ORD('A'), $C01E0001); <br>-------------------------------- <br> PostMessage(Edit1.Handle, WM_CHAR, ORD('A'), $C01E0001); <br>-------------------------------- <br> PostMessage(Edit1.Handle, WM_KEYDOWN, VK_SHIFT , $002A0001); <br> PostMessage(Edit1.Handle, WM_KEYDOWN, ORD('A'), $001E0001); <br> PostMessage(Edit1.Handle, WM_KEYUP, ORD('A'), $C01E0001 ); <br> PostMessage(Edit1.Handle, WM_KEYUP, VK_SHIFT, $C02A0001 ); <br>--------------------------------- <br> SendMessage(Edit1.Handle, WM_CHAR, ORD('a'), $C01E0001); <br> <br> 等等 。。。。。。。。。 <br> <br> <br>来自: 刘麻子, 时间: 2004-08-11 12:21:06, ID: 2759214 <br>按键类消息的 两个参数值都是类似的 , 前一个参数是 虚拟键键值 , <br>后一个是一些位的组合,根据帮助上的说明我们自己也可以组合出来。 <br>不过为了方便,我把以前写的键盘钩子DLL代码改了一下,直接显示出来: <br><br>动态连接库DllP.dpr代码 : <br>library DllP; <br><br>uses windows,SysUtils; <br><br><br>var <br> HookH:HHook; //钩子句柄 <br><br>procedure liumazi(V:string;LEFT,TOP:integer); <br>var <br> FileH : Longint; //文件句柄 <br> FSize : Longint; //写文件字节数 <br> Wsize : Longword; //返回实际写入字节数 <br> DC:HDC; <br>begin <br>//--写到屏幕上 <br> DC:=GetDC(0); <br> TextOut(DC,LEFT,TOP,Pchar(V),Length(V)); <br> ReleaseDC(0,DC); <br>//---为了看得更清楚写到文件中 <br> V:=V+#13#10; <br> FileH:=CreateFile(PChar('c:/log.txt'), GENERIC_READ or GENERIC_WRITE, <br> 0, nil, Open_Always, FILE_ATTRIBUTE_NORMAL, 0); <br> SetFilePointer(FileH, 0 , nil, 2); <br> FSize:=Length(V); <br> WriteFile(FileH, V[1] , FSize, Wsize, nil); <br> CloseHandle(FileH); <br>end; <br><br>function keyhook(Code:Integer;wParam:WPARAM;lParam:LPARAM):LRESULT;stdcall; <br>begin <br> if(((LParam shr 31)and 1)=0) then <br> begin <br> Liumazi('Down LParam:'+InttoHex(lparam,8)+' ',100,100); <br> Liumazi('Down WParam:'+InttoHex(Wparam,8)+' ',100,120); <br> end <br> else <br> begin <br> Liumazi('up LParam:'+InttoHex(lparam,8)+' ',100,200); <br> Liumazi('up WParam:'+InttoHex(Wparam,8)+' ',100,220); <br> end; <br> Result:=CallNextHookEx(HookH,code,Wparam,lParam); <br>end; <br><br>procedure HookOn; <br>begin <br> HooKH:=SetWindowsHookEx(WH_KEYBOARD,keyHook,HInstance,0); <br>end; <br><br>procedure HookOff; <br>begin <br> UnHookWindowsHookEx(HookH); <br>end; <br><br><br>exports <br> HookOn,HookOff; <br><br>begin <br>end. <br><br><br>简单调用范例keyhook.dpr代码 : <br>program keyhook; <br><br>uses <br> Windows; <br><br>var <br> Msg: TMsg; //消息结构 <br><br>procedure HookOn; stdcall; external 'DllP.dll'; <br>procedure HookOff; stdcall; external 'DllP.dll'; <br> <br>begin <br> hookon; //挂键盘钩子 <br> While GetMessage(Msg, 0, 0, 0) do; <br>end. <br><br> <br>来自: 刘麻子, 时间: 2004-08-11 12:24:18, ID: 2759222 <br>用其他类型得钩子也可以 还可进一步区分具体是什么消息 。 <br> <br>来自: thx1180, 时间: 2004-08-11 12:28:29, ID: 2759228 <br>我看这个问题的关键是发送到哪里?如果目标窗口没有焦点怎么发都是白搭,只有焦点窗口Windows才会发键盘消息的[8D] <br> <br>来自: 刘麻子, 时间: 2004-08-11 13:02:40, ID: 2759285 <br>呵呵,请楼上的试验之后再说话。我测试了,是可以的。 <br>实在不行,可调用AttachThreadInput 附加线程输入处理器 <br>但是这里楼主主要问的是怎么发组合键消息?特别是Alt+XXX <br> <br>来自: 刘麻子, 时间: 2004-08-11 13:18:43, ID: 2759341 <br>thx1180 老大 : <br><br>是的,通常情况下当我们按下键的时候,只有 当前具有焦点的窗口才响应, <br>因为windows只会往当前焦点窗口所属的线程的消息队列放诸如 WM_KEYDOWN 消息, <br>然后经过线程中执行 TranslateMessage 转换成合适的 WM_CHAR 并且放到消息队列中 <br>下次再取消息取到WM_CHAR的时候,就得到字符了。。。 <br><br>但是请注意,这里的消息不是当我们按下键,依靠windows发给我们的,而是我们自己发的。 <br><br>关键之处就在于是目标窗口处理到一个WM_CHAR即可。 <br><br>那么我们可以PostMessage WM_KEYDOWN把消息放到句柄所处得线程消息队列中 <br>(随后由他自己调用TranslateMessage 转换成WM_CHAR) <br><br>或者PostMessage WM_CHAR,当这个消息从消息队列取出来之后,会被分发到指定 <br>句柄的处理过程,这个和上面类似,只是省略了WM_KEYDOWN ,相当于模仿TranslateMessage <br><br>或者直接SendMessage WM_CHAR 因为这样是直接找到句柄对应的处理过程并且调用, <br>上面PostMessage最终也要走这一步,就是调用 句柄对应的处理过程 。。 <br><br>但是,我一再强调,如果SendMessage WM_KEYDOWN 就不行.因为没有经过消息队列,不会产生WM_CHAR. <br> <br>来自: meteor007, 时间: 2004-08-11 13:21:46, ID: 2759354 <br>用hook 太麻烦 同意楼上 <br> PostMessage(yourhandle, WM_KEYDOWN, VK_SHIFT , $002A0001); <br> PostMessage(yourhandle, WM_KEYDOWN, ORD('A'), $001E0001); <br> <br><br> <br>来自: thx1180, 时间: 2004-08-11 13:28:37, ID: 2759367 <br>To:刘麻子 <br> 请你也不要乱猜,你以为我没有实验过就乱说么?我早就做过键盘Hook了,你的键盘Hook能把收到的键盘消息转发出来么? <br> <br>来自: 刘麻子, 时间: 2004-08-11 13:28:57, ID: 2759369 <br><br>没有说用Hook,我写的hook代码是为了测试每个按键消息的参数值,反正也写了, <br>就贴出来给楼主看一下,方便而已。你们好像都不看清楚就说的啊?晕!!! <br><br>“来自:刘麻子, 时间:2004-8-11 12:21:06, ID:2759214 | 编辑 <br>按键类消息的 两个参数值都是类似的 , 前一个参数是 虚拟键键值 , <br>后一个是一些位的组合,根据帮助上的说明我们自己也可以组合出来。 <br>不过为了方便,我把以前写的键盘钩子DLL代码改了一下,直接显示出来:” <br> <br>来自: thx1180, 时间: 2004-08-11 13:35:00, ID: 2759382 <br>To:刘麻子 <br> 请你也看清楚了,我说的也不是Hook的问题,而是说“我看这个问题的关键是发送到哪里?如果目标窗口没有焦点怎么发都是白搭,只有焦点窗口Windows才会发键盘消息的” <br> <br>来自: 刘麻子, 时间: 2004-08-11 13:36:33, ID: 2759386 <br>关于拦截和转发可以看 : http://www.delphibbs.com/delphibbs/dispq.asp?lid=2690393 <br> (其中拦截到空格键时给有焦点窗口发送V键被按下消息<作为示范>
<br><br>如果是想转成汉字可以看看 http://Liumazi.efile.com.cn 的 ShuRuFa.rar . <br><br>当时的要求都是发给当前焦点控件,但是仅仅是句柄不同而已,只要句柄对了,就可以。 <br> 怎么找句柄不用我说了吧?呵呵,不同情况下是不同的。 <br> <br>来自: 刘麻子, 时间: 2004-08-11 13:51:50, ID: 2759391 <br>请您冷静下来仔细看看我上面的描述,已经说了很详细了,而且都是作了试验才贴出来的。 <br><br>您说的 “焦点窗口Windows才会发键盘消息的” 啥意思 ?? 如果是按键盘是这样的,但是这里是直接发消息。 <br><br>难道是说我的方法不行嘛?只要窗体过程处理到了 WM_CHAR 消息就相当于 按键盘了。 <br>注意 这里消息不是windows发的,是我们自己发的。相当于手工干预。 <br><br>您可以作一个最简单的试验,开一个有edit的程序,记下edit的句柄,然后启动delphi <br>,建立一个窗体、一个按钮,按钮事件中 用我说的方法中的任意一种,发一个A试试。 <br>当然句柄要指定为那个edit的 。。。 <br><br>仅是讨论,希望不要生气。我可能有错误的地方,欢迎指正。但请拿出证据,举例说明。 <br> <br>来自: thx1180, 时间: 2004-08-11 13:51:41, ID: 2759419 <br>嘿嘿,不知道到底是谁看不清楚 <br> <br>来自: 刘麻子, 时间: 2004-08-11 14:33:00, ID: 2759509 <br> 老大 不要光冷笑嘛,呵呵。这里楼主主要问的是怎么发这个消息, <br>而我觉得我已经把个个环节分析得非常详细了。 <br><br>然后您突然跳出来说一句:“没焦点windows就不会发键盘消息” 这句话就是不对的, <br>我上面说的那个试验您作了嘛? 难道edit没有多一个字符A吗?这里的按键消息不是 <br>windows发的,一个按键消息也不是windows发的,是我们直接发的。 <br><br>没猜错的话,我估计您作的试验,可能是 放了一个菜单 ,然后设置其热键 <br>为 ALT+A ,确实,菜单没有出来,但这并不代表没有收到按键消息,而可能 <br>是其他原因,比如窗体没有能力把自身提到前面来,那么可以这么写: <br><br>procedure TForm1.Button1Click(Sender: TObject); <br>var <br> threadld:dword; <br>begin <br> threadld:=GetWindowThreadProcessId(17565198,nil); <br> AttachThreadInput(GetCurrentThreadId,threadld,true); <br> PostMessage(17565198, WM_SYSCHAR, ORD('A'), $201E0001); <br> SetForegroundWindow(17565198); //窗体提前 <br> AttachThreadInput(GetCurrentThreadId,threadld,false); <br>end; <br><br> <br>来自: leiming000001, 时间: 2004-08-11 15:31:58, ID: 2759672 <br>to 刘麻子 <br>我严重支持刘麻子:) <br> <br>来自: 刘麻子, 时间: 2004-08-11 15:40:39, ID: 2759697 <br>菜单没有弹出 不代表没有收到按键消息 这只是表面现象 编译下面这个程序 <br><br>unit Unit1; <br><br>interface <br><br>uses <br> Windows, Messages, Forms, Dialogs, Classes, Menus; <br><br>type <br> TForm1 = class(TForm) <br> procedure MyProc(Var MSG :TMSG );message WM_SYSCHAR; <br> end; <br><br>var <br> Form1: TForm1; <br><br>implementation <br><br>{$R *.dfm} <br><br>procedure TForm1.MyProc(Var Msg: TMSG ); <br>var <br> threadld:dword; <br>begin <br>{ threadld:=GetWindowThreadProcessId(Self.Handle,nil); <br> AttachThreadInput(GetCurrentThreadId,threadld,true); <br> SetForegroundWindow(Self.Handle); //窗体提前 <br> AttachThreadInput(GetCurrentThreadId,threadld,false); } <br> showmessage('fgfgfgfgf'); <br>end; <br>end. <br><br>然后写另一个程序,PostMessage(窗体句柄,WM_SYSCHAR,ORD('A'),$201E0001);看看? <br> <br>来自: xuhao1, 时间: 2004-08-11 15:57:30, ID: 2759763 <br>多人接受答案了。 <br> <br>来自: thx1180, 时间: 2004-08-12 14:11:41, ID: 2761503 <br>>>没猜错的话,我估计您作的试验,可能是 放了一个菜单 ,然后设置其热键为 ALT+A <br><br>这个叫“刘麻子”的家伙除了瞎猜还会什么?自以为是!!!! <br> <br>得分大富翁: wen00000000-5,风铃夜思雨-5,刘麻子-40,