-1

I need to send several virtual keys (VK_RETURN) from my delphi application (myapp.exe) into another application (target.exe). Eg : Send VK_RETURN twice , from myapp.exe , into target.exe

The OS that I use are Windows 7 64 bit and Windows XP.

I read : How to send an "ENTER" key press to another application? , Send Ctrl+Key to a 3rd Party Application (did not work for me) and other previous asked question. But still I'm getting confused.

How to set the focus to the target application ?

How to send the virtual keys to the targeted application ?

Simple example : I want to send VK_RETURN twice into notepad.exe or calc.exe (already loaded) or any other program from my delphi application. How to do that ?

The simplest way to do this in Delphi 2010, please...

PS : I tried SndKey32.pass from http://delphi.about.com/od/adptips2004/a/bltip1104_3.htm And got error : [DCC Error] SndKey32.pas(420): E2010 Incompatible types: 'Char' and 'AnsiChar'

  If (Length(KeyString)=1) then MKey:=vkKeyScan(KeyString[1])
Community
  • 1
  • 1
Galvion
  • 1,353
  • 7
  • 23
  • 35

1 Answers1

5

If your target application isn't the foreground window, you need to use PostMessage to send keystrokes to its window handle. You can get that window handle using FindWindow. The code below sends the Enter key to a the text area in a running instance of Notepad (note it uses an additional FindWindowEx to locate the memo area first). It was tested using both Delphi 2007 and Delphi XE4 (32-bit target) on Windows 7 64.

uses Windows;
    
procedure TForm1.Button1Click(Sender: TObject);
var
  NpWnd, NpEdit: HWnd;
begin
  NpWnd := FindWindow('Notepad', nil);
  if NpWnd <> 0 then
  begin
    NpEdit := FindWindowEx(NpWnd, 0, 'Edit', nil);
    if NpEdit <> 0 then
    begin
      PostMessage(NpEdit, WM_KEYDOWN, VK_RETURN, 0);
      PostMessage(NpEdit, WM_KEYUP, VK_RETURN, 0); 
    end;
  end;
end;

To find the window by title (caption) instead, you can just use the second parameter to FindWindow. This finds a new instance of Notepad with the default 'Untitled' file open:

NpWnd := FindWindow(nil, 'Untitled - Notepad');

Note that this requires as exact match on the window title. An extra space before or after the -, for instance, will cause the match to fail and the window handle to not be retrieved.

You can use both the window class and title if you have multiple instances running. To find the copy of Notepad running with Readme.txt loaded, you would use

NpWnd := FindWindow('Notepad', 'Readme.txt - Notepad');

To find other applications, you'll need to use something like WinSpy or WinSight to find the window class names. (There are others also, such as Winspector or WinDowse (both of which are written in Delphi).)

Your comment mentions Calculator; according to Winspector, the Calculator main window is in a window class called CalcFrame on Windows 7, and the area the numbers are displayed in is a Static window (meaning it doesn't seem to receive keystrokes directly). The buttons are simply called Button, so you'd have to loop through them using EnumChildWindows looking for the individual buttons to identify them in order to obtain their handles.

(How to enumerate child windows is a separate question; you can probably find an example by searching here or via Google. If you can't, post a new, separate question about that and we can try to get you an answer.)

Here's a quick example of sending keys to Calculator after finding it by window class. It doesn't do anything useful, because it needs some time spent to identify different buttons and the keys that each responds to (and the proper combination of messages). This code simply sends 11Numpad+22 to the calculator window (a quick test showed that they were properly received and displayed, and that's about all the time I wanted to spend on the process).

uses Windows;

procedure TForm1.Button1Click(Sender: TObject);
var
  NpWnd: HWnd;
begin
  NpWnd := FindWindow('CalcFrame',  nil);
  if NpWnd <> 0 then
  begin
    PostMessage(NpWnd, WM_KEYDOWN, VK_NUMPAD1, 0);
    PostMessage(NpWnd, WM_KEYDOWN, VK_ADD, 0);
    PostMessage(NpWnd, WM_KEYDOWN, VK_NUMPAD2, 0);
  end;
end;
Shaun Roselt
  • 1,650
  • 5
  • 18
  • 44
Ken White
  • 123,280
  • 14
  • 225
  • 444
  • yes, it works in notepad. But what about with other application ? I have an application, named DKQC.EXE and DKQG.EXE which I want to send twice keystroke of Enter (VK_Return) inside the DKQG.EXE for a button and its confirmation message, to replace the mouse click. – Galvion Aug 11 '13 at 03:30
  • or maybe you can test the script with acdess12.exe, where to open a folder we press return / enter. and to open a file within, we press another enter (twice enter). how to make it work in ACDSee12.exe ? coz your script works on notepad only. – Galvion Aug 11 '13 at 04:16
  • My "script" (it's not script, it's code) works on Notepad because that's what it looks for specifically (and what [you asked for](http://stackoverflow.com/questions/18163619/how-to-send-virtual-keys-to-other-application-using-delphi-2010/18164307?noredirect=1#comment26609189_18163619)). If you need it to work for another application, you need to figure out what window class you need to look for - I'm not installing software I don't need on my computer to figure it out for you. :-) Search for WinSpy or WinSight, which can help you find that information (the same way I did for Notepad). – Ken White Aug 11 '13 at 04:32
  • Does this work for all cases? I'm thinking that UIPI in Vista+ would block code like this in the case of the target application being run under elevated privileges with respect to the code above (ie : user code posting to something run as administrator, etc). – J... Aug 11 '13 at 23:47
  • @J: Probably not, but the question didn't ask for something working across privilege boundaries. It specifically asked about sending two enter keys, and in the comments said "to notepad.exe". I'm pretty sure that almost nothing "works in all cases"; I'm sure most things can have an edge case where something doesn't work. :-) Almost nothing works across privilege boundaries going from lower to higher privileges; if they did, it would be a major security hole. – Ken White Aug 11 '13 at 23:55
  • @ken : Thank you for the source code for notepad. You do not need to Install the apps. Because your code works at notepad, but when I try it on calc.exe (windows calculator), it does not work. Its more like that FindWindow and FindWindowEx can not find the "calc.exe", but it can find the "notepad.exe" (I use Process Explorer. And I have the admin control in my login.) – Galvion Aug 15 '13 at 07:20
  • Or maybe is there any code to find the find the app based on windows title, not just window class ? Because I try to replace the 'Notepad' with 'SciCalc' and I works or able to send the keystroke to the calc.exe. But when I replace it with 'TDkForm' it can recognize the TDkForm, but can not send the keystroke to the application that I want. Any idea to find the app based on windows class and windows title ? – Galvion Aug 15 '13 at 07:43
  • 1
    I linked you to the documentation, and gave you information on WinSpy and WinSight (there's also WInspector and WinDowse). If you're going to use the WinAPI to do things, sometimes you need to read the documentation and figure things out. I'll update my code to also send a couple of numeric keys to Calc (and find it by name), but after that you need to use the tools I've given you and spend some time trying to figure this out yourself. :-) – Ken White Aug 15 '13 at 14:12
  • @ShaunRoselt: Windows sends them based on input from the user. – Ken White Oct 10 '20 at 05:31
  • @KenWhite Yes, but I was asking what unit is WM_KEYDOWN and WM_KEYUP contained in. So what must you under your uses list to use them. – Shaun Roselt Oct 12 '20 at 14:17
  • 1
    @ShaunRoselt: They're defined in Windows.pas. – Ken White Oct 12 '20 at 15:59