Simulating keyboard input in Delphi using WinAPI
Asked Answered
F

2

10

I need to programmatically enter one character into a cell of a Delphi grid (in other application).

In order to do this manually, following steps are required:

  1. Press the F3 button.
  2. Press the right-arrow key 3 times.
  3. Press the space button.
  4. Type letter 'E' on the keyboard.
  5. Press the right-arrow key.

     // Press F3 button         
     keybd_event(VK_F3, 0, 0, 0);         
     // Press right arrow key 3 times
     keybd_event(VK_RIGHT, 0, 0, 0);
     keybd_event(VK_RIGHT, 0, 0, 0);
     keybd_event(VK_RIGHT, 0, 0, 0);
    
     // Press the space button
     keybd_event(VK_SPACE, 0, 0, 0);
    
     // Type letter E
     keybd_event(Ord('E'), 0, 0, 0);
    
     // Move to the right
     keybd_event(VK_RIGHT, 0, 0, 0);
    

But it doesn't work. When I run this code, nothing seems to happen.

How should I modify this code so that it actually simulates user input?

Foregone answered 18/10, 2012 at 9:4 Comment(5)
I've made something about virtual keyboard some time ago (and there will be many others). But to your problem, if you are targeting TStringGrid, I think you can't do anything else than focus it and simulate your keystrokes (if I remember that right, TStringGrid doesn't respond to any kind of message that would be able to set the text of a cell).Adequacy
In this particular application it is possible to enter values into that grid only via keyboard. I've done this already with AutoHotKey and MS UI Automation, but now need to rewrite this code in Delphi.Foregone
I can't rely on the grid being focused because there is a program on the target system, which activates itself every 200 milliseconds.Foregone
You can try to use the WM_KEYDOWN, WM_KEYUP messages, but I'm not sure it will always work between two processes...Adequacy
Here is un example (with source code) of autoclic that simulates keystrokes and mouse clicks and then play them in a sequence. delphimagic.blogspot.com.es/2010/03/autoclic-con-delphi.htmlManxman
B
19

Each key press is a key down and then a key up. So you need two calls to keybd_event per key press. For example, to press F3:

keybd_event(VK_F3, 0, KEYEVENTF_KEYDOWN, 0);
keybd_event(VK_F3, 0, KEYEVENTF_KEYUP, 0);

Note that KEYEVENTF_KEYDOWN isn't actually defined by the Windows header files, or the Delphi translation. Define it to be 0. It makes the code clearer written out explicitly though.

Naturally you would not litter your code with paired calls to keybd_event. But instead you would wrap up the paired calls into a helper function.

It's possible that in some situations you would need to specify the second parameter, the scan code. But it's often not necessary.

Bakelite answered 18/10, 2012 at 9:10 Comment(8)
Thanks. Does keybd_event work, when the control in question is NOT focused?Foregone
@DmitriPisarenko Not it does not. Input messages go to the control with the input focus.Bakelite
Is it possible to replace keybd_event calls with sending windows messages to the grid?Foregone
@DmitriPisarenko Probably. Use PostMessage with WM_KEYDOWN and WM_KEYUP.Bakelite
Regarding lParam of WM_KEYUP message. According to msdn.microsoft.com/en-us/library/windows/desktop/… there are 3 1-bits in lParam, which gives me a value of 0x8000C. Reason: dl.dropbox.com/u/11776689/2012_10_18_delphi_winapi_bits.png Is this correct?Foregone
That's a different question altogether. I think I answered the question that you asked.Bakelite
Ad lParam for WM_KEYUP: It seems to be 0xC0000001.Foregone
It is, but I wanted to make sure that everything works as it should. In the meantime, I encountered and fixed another problem ( #12955045 ). Now the code seems to do what it should and I marked the question as answered.Foregone
G
0

Use https://github.com/WladiD/SendInputHelper by Mr. Waldemar Derr.

Example:

uses
  ..., SendInputHelper;

procedure TForm1.Button1Click(Sender: TObject);
var
  SIH: TSendInputHelper;
begin
  SIH := TSendInputHelper.Create;
  try
    // Start command shell
    SIH.AddShortCut([ssWin], 'r'); // Win+R
    SIH.AddDelay(100);
    SIH.AddText('cmd', True); // Second parameter True means AppendReturn
    SIH.AddDelay(500);

    SIH.AddText('ping google.de', True); // Perform a ping.

    SIH.Flush; // Isn't it easy?
  finally
    SIH.Free;
  end;
end;
Gina answered 27/9, 2022 at 2:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.