请教,怎么样模拟键盘操作外部程序.(发送字符串).(100分)

  • 主题发起人 主题发起人 huying
  • 开始时间 开始时间
H

huying

Unregistered / Unconfirmed
GUEST, unregistred user!
我想模拟键盘的简单操作!就是把执行文件打开后,原来是需要手动的操作.(在打开的EXE外部程序上的EDIT填写路径之类).但是我现在想模拟键盘自动操作它,当然步骤是固定的.现在我能实现向EXE外部程序发送TAB,RETURN等键.但是不能发送字符串,(当TAB后焦点在EXE的EDIT上,这个时候应该给其填上路径).此时我应该是发送路径的字符串.可是无法实现.请教各位高手,应该怎么发送才能在外部EXE的EDIT上填上呢?我是这样写的.但是不对!
s:='c:/60s.bin';
for i := 1 to length(s) do begin
keybd_event(ord(s), MapVirtualKey(ord(s), 0), 0, 0);
keybd_event(ord(s), MapVirtualKey(ord(s), 0), KEYEVENTF_KEYUP, 0);
end;
 
获得当前焦点控件的Handle,然后直接用WM_SETTEXT设置Edit的内容——最省力了。
还可以设定剪贴板的内容为要输入的文本,然后发送WM_PASTE(或者模拟Ctrl+V)。

如果不想用别的招术,老老实实的模拟键盘操作,请看1440273号帖子。
 
谢谢大哥的回复,1440273号帖子我仔细看了.我就是按他的方法发送的回车,TAB等键.但是我要往外部程序(xxx.exe)上的edit填字符串就搞不定了(只需填上路径).你说的第一种方法,是要获得外部程序焦点控件的handle吗?怎么样获得呢?应该怎么实现呢?同样第2种方法又应该怎么实现呢?能不能给小弟个例子.写下代码!感谢了!
 
我看到有位大哥这样说的!用EnumWindows根据目标窗口的标题找到它的句柄,再用EnumChildWindows找到Edit的句柄,然后SendMessage WM_SetText.这样好象可以.但是问题又出现了.因为我的外部程序上有2个EDIT,分别是2个路径.而找到EDIT句柄再修改的话,会同时把2个一同修改了.怎么样单独修改呢?代码如下:希望高手指教!
function EnumWindowsProc(Hwnd:THandle;lParam:LParam):boolean;
var
WindowCaption:array[0..254] of Char;
begin
GetWindowText(Hwnd,WindowCaption,255);
if StrPas(WindowCaption)='MXIC Speech Utility' then
begin
cnt := 0;
EnumChildWindows(Hwnd,@EnumChildProc,0);
Result := False;
Exit;
end;
Result := True;
end;

function EnumChildProc(Hwnd:THandle;lParam:LParam):boolean;
var
WindowCaption,WindowClass:array[0..254] of Char;
begin
GetClassName(Hwnd,WindowClass,255);
if Pos('EDIT',UpperCase(StrPas(WindowClass))) > 0 then
begin
Inc(cnt);
SendMessage(Hwnd,WM_SETTEXT,0,LongInt(PChar(s)));
////此处换成SendMessage(Hwnd,WM_SETTEXT,0,LongInt(PChar('你想送的字符串')));即可
end;
Result := True;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
aHandle:THandle;
i:integer;
s1:string;
begin
shellexecute(aHandle,'open','c:/MSU.exe',nil,'',sw_shownormal);
timedelay(1000);
Wnd := FindWindow(nil,'MXIC Speech Utility');
if Wnd <> 0 then
begin
SetForegroundWindow(Wnd);
s:='c:/60s.bin';
Enumwindows(@EnumWindowsProc,0); //往外部EXE的第一个EDIT填第一个路径

for i:=1 to 2 do //--2个tab
begin
keybd_event(VK_Tab, MapVirtualKey(VK_Tab, 0), 0, 0);
keybd_event(VK_Tab, MapVirtualKey(VK_Tab, 0), KEYEVENTF_KEYUP, 0);
end;

s:='c:/60s.wav';
Enumwindows(@EnumWindowsProc,0); //往外部EXE的第2个EDIT填第2个路径
 
在回调过程中得到Edit的句柄后,可以进一步获得它的坐标的——根据坐标来判断是否设
定文本以及采用什么文本。
 
那怎么样分别得到2个EDIT的坐标从而分别发送2个不同的字符串呢??大哥,能在小弟给出的代码里修改吗?现在小弟的代码是同时修改2个EDIT.所以结果变成了2个EDIT里面的路径是一样的了(都是最后一次的值).能帮忙改下吗?谢谢了!
 
var
MyRect:TRect;
...
GetWindowRect(Hwnd,MyRect);
//ShowMessage(Format('%d,%d',[MyRect.Left,MyRect.Top])); //首先用这一句来查看控件坐标
if (MyRect.Left=888) and (MyRect.Top=222) then //这一行要用到检测到的坐标
SendMessage(Hwnd,WM_SETTEXT,0,LongInt(PChar('字符串 1')))
else
SendMessage(Hwnd,WM_SETTEXT,0,LongInt(PChar('字符串 2')));
 
谢谢大哥,我按你说的修改成这样:
function EnumChildProc(Hwnd:THandle;lParam:LParam):boolean;
var
WindowCaption,WindowClass:array[0..254] of Char;
MyRect:TRect;
begin
GetClassName(Hwnd,WindowClass,255);
if Pos('EDIT',UpperCase(StrPas(WindowClass))) > 0 then
begin
Inc(cnt);
GetWindowRect(Hwnd,MyRect);
//ShowMessage(Format('%d,%d',[MyRect.Left,MyRect.Top])); //首先用这一句来查看控件坐标
if (MyRect.Left=600) and (MyRect.Top=235) then //通过ShowMessage得到的坐标.
SendMessage(Hwnd,WM_SETTEXT,0,LongInt(PChar(s)))
else
SendMessage(Hwnd,WM_SETTEXT,0,LongInt(PChar(s)));
end;
Result := True;
end;
但问题还是一样!~还是会同时修改2个EDIT.大哥,你可不可以直接在我给出的代码里修改呢!可能我没改对!我实在太菜了.麻烦大哥了!
 
if (MyRect.Left=600) and (MyRect.Top=235) then //通过ShowMessage得到的坐标.
SendMessage(Hwnd,WM_SETTEXT,0,LongInt(PChar(s)))
else
SendMessage(Hwnd,WM_SETTEXT,0,LongInt(PChar(s)));

匹配无论成功还是失败都改成S——好歹分一下S1,S2吧?不能只用一个变量那么吝啬吧?
 
用2个变量效果就好了.但是虽然字符串(路径)填上了,但是还是不能完整操作外部EXE,是不是模拟键盘传送路径和手动操作EXE直接填有不同呢.是不是SendMessage(Hwnd,WM_SETTEXT,0,LongInt(PChar(s)));改变了EXE的内部的什么东西!改变了窗体内部的参数了呢?(用手动操作和用这种方法发送EXE显示上有点不同).是不是用你说的第2种方法好些呢,不会修改窗体!只是对EDIT赋值呢?
大哥,能和你用即时通讯工具交流吗?
 
小弟又在想,用第2种方法.把路径放到剪贴板上,然后用keybd_event模拟Ctrl+v是不是就稳定点!但是小弟不知道应该怎么把剪贴板里的内容复制下来再模拟Ctrl+v.只写了这样的垃圾代码?请大哥指教!我都不好意思贴!
ss:='c:/60s.wav';
clipboard.AsText:=ss;
keybd_event( VK_CONTROL, MapVirtualKey( VK_CONTROL, 0 ), 0 , 0 );
keybd_event( byte('v'), MapVirtualKey( byte('v'), 0 ), 0 , 0 );
keybd_event( byte('v'), MapVirtualKey( byte('v'), 0 ), KEYEVENTF_KEYUP , 0 );
keybd_event( VK_CONTROL, MapVirtualKey( VK_CONTROL, 0 ), KEYEVENTF_KEYUP , 0 );
 
WM_SETTEXT是非常标准的消息,应该不会有问题的。在1440273号帖子中我给出了利用自
带的sndkey32.pas中的函数的方案,非常方便,为什么楼主还是盯着keybd_event不放呢?
 
小弟是通过setup.exe安装的Delphi.没有sndkey32.pas.小弟也想用最简单的实现!
可是小弟按大哥上面说的我效果实现了啊.赋值上了啊~已经填上了!但是EXE好象内部参数什么的(很奇怪).但是我手动能C+c和C+v.所以那我模拟C+c和C+v就一定行.对吧!
大哥加我了吗?QQ:25220064
 
多人接受答案了。
 

Similar threads

I
回复
0
查看
782
import
I
D
回复
0
查看
2K
DelphiTeacher的专栏
D
D
回复
0
查看
1K
DelphiTeacher的专栏
D
D
回复
0
查看
2K
DelphiTeacher的专栏
D
后退
顶部