Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to programmatically press a key exactly the same as if it were pressed on a keyboard?

Does anyone know how to programmatically press a key exactly the same as if it were pressed on a keyboard? PostMessage fails, SendInput fails, keybd_event fails, SendMessage fails and I even tried the unusual way of mimicing a key press using the Vcl.Touch.Keyboard. I even wrote a quick vb script file calling sendkeys which also failed. I have been have having trouble trying doing this on a program called Sellerdeck http://www.sellerdeck.com/

I have tried all of the following, they all work with notepad but fail on this program. The window is successfully brought to the forground by

procedure bringToForegroung;
Var
findhandle1 : cardinal;
begin
findhandle1 := FindWindow(NIL, 'Business Plus - Test site: Online Catalogue');
ShowWindow(findhandle1,SW_SHOW);
SetForegroundWindow(findhandle1);
end;

1.

procedure SendF10;
Var
findhandle1 : cardinal;
begin
findhandle1 := FindWindow(NIL, 'Business Plus - Test site: Online Catalogue');
ShowWindow(findhandle1,SW_SHOW);
SetForegroundWindow(findhandle1);
PostMessage(findhandle1, WM_KEYDOWN, VK_F10, 0);
PostMessage(findhandle1, WM_KEYUP, VK_F10, 0);
end;

2.

 procedure SendAltF;
var
  KeyInputs: array of TInput;
  //--------------------------------------------
  procedure KeybdInput(VKey: Byte; Flags: DWORD);
  begin
    SetLength(KeyInputs, Length(KeyInputs)+1);
    KeyInputs[high(KeyInputs)].Itype := INPUT_KEYBOARD;
    with  KeyInputs[high(KeyInputs)].ki do
    begin
      wVk := VKey;
      wScan := MapVirtualKey(wVk, 0);
      dwFlags := Flags;
    end;
  end;
begin
  KeybdInput(VK_MENU, 0);                 // Alt
  KeybdInput(Ord('F'), 0);
  KeybdInput(Ord('F'), KEYEVENTF_KEYUP);
  KeybdInput(VK_MENU, KEYEVENTF_KEYUP);   // Alt
  SendInput(Length(KeyInputs), KeyInputs[0], SizeOf(KeyInputs[0]));
end;

3.

procedure SendKey2(Wnd,VK : Cardinal; Ctrl,Alt,Shift : Boolean);
var
  MC,MA,MS : Boolean;
begin
  // Try to bring target window to foreground
  ShowWindow(Wnd,SW_SHOW);
  SetForegroundWindow(Wnd);

  // Get current state of modifier keys
  MC:=Hi(GetAsyncKeyState(VK_CONTROL))>127;
  MA:=Hi(GetAsyncKeyState(VK_MENU))>127;
  MS:=Hi(GetAsyncKeyState(VK_SHIFT))>127;

  // Press modifier keys if necessary (unless already pressed by real user)
  if Ctrl<>MC then keybd_event(VK_CONTROL,0,Byte(MC)*KEYEVENTF_KEYUP,0);
  if Alt<>MA then keybd_event(VK_MENU,0,Byte(MA)*KEYEVENTF_KEYUP,0);
  if Shift<>MS then keybd_event(VK_SHIFT,0,Byte(MS)*KEYEVENTF_KEYUP,0);

  // Press key
  keybd_event(VK,0,0,0);
  keybd_event(VK,0,KEYEVENTF_KEYUP,0);

  // Release modifier keys if necessary
  if Ctrl<>MC then keybd_event(VK_CONTROL,0,Byte(Ctrl)*KEYEVENTF_KEYUP,0);
  if Alt<>MA then keybd_event(VK_MENU,0,Byte(Alt)*KEYEVENTF_KEYUP,0);
  if Shift<>MS then keybd_event(VK_SHIFT,0,Byte(Shift)*KEYEVENTF_KEYUP,0);
end;

4.

procedure SendF10v2;
Var
findhandle1 : cardinal;
begin
findhandle1 := FindWindow(NIL, 'Business Plus - Test site: Online Catalogue');
ShowWindow(findhandle1,SW_SHOW);
SetForegroundWindow(findhandle1);
SendMessage(findhandle1, WM_KEYDOWN, VK_F10, 0);
SendMessage(findhandle1, WM_KEYUP, VK_F10, 0);
end;

5.

uses
  Vcl.Touch.Keyboard, Vcl.Touch.KeyboardTypes;
type
    procedure FormCreate(Sender: TObject);
protected        {i.e. dont make form active}
    procedure CreateParams(var Params: TCreateParams); override; {i.e. dont make keyboard form active}


procedure TForm1.CreateParams(var Params: TCreateParams);
 begin
  inherited CreateParams(Params);
  with Params do
  begin
    ExStyle   := ExStyle or WS_EX_NOACTIVATE;
    WndParent := GetDesktopwindow;
  end;
end;

procedure TForm1.SpeedButton1Click(Sender: TObject);
var
  KeyData: TKeyData;
begin
KeyData := VKey(VK_F10, -1);
SendKey(KeyData, ksDown);
SendKey(KeyData, ksUp);
end;

6. (VBS)

Option Explicit
Dim objShell
Set objShell = CreateObject("WScript.Shell")
objShell.Run """C:\Program Files (x86)\SellerDeck 2013\Catalog.exe"" /s ""Test site"" /n Administrator /w Administrator", 0, True
Wscript.Sleep 10000
objShell.SendKeys "%F"
Wscript.Sleep 1000
objShell.SendKeys "%F"
Wscript.Sleep 1000
objShell.SendKeys "%F"
Wscript.Sleep 1000
objShell.SendKeys "%F"
Wscript.Sleep 1000
objShell.SendKeys "%F"
Wscript.Sleep 1000
objShell.SendKeys "%F"
WScript.Quit 

As I said all, of these work in notepad, otherwise I would think it was my PC that was the problem. I am trying to automate some basic tasks on this Sellerdeck program. Is there anyway to exactly mimic a key press? I hope it is just that I am missing something really basic.

like image 917
MattB Avatar asked Nov 03 '14 11:11

MattB


2 Answers

My guess is that you are sending the commands to the wrong Window handle. Perhaps the main application window, returned by FindWindow(), is not the one handle keystokes.

Try to use a debug tool, like WinSight (ws32.exe - which was shipped in older versions of Delphi), to guess the right handle...

like image 167
Arnaud Bouchez Avatar answered Sep 29 '22 10:09

Arnaud Bouchez


The following code works fine for me:

procedure TForm1.Button1Click(Sender: TObject);
begin
  keybd_event(VK_MENU, $b8, 0, 0);
  keybd_event(VK_F4, $8f, 0, 0);
  keybd_event(VK_F4, $8f, KEYEVENTF_KEYUP, 0);
  keybd_event(VK_MENU, $b8, KEYEVENTF_KEYUP, 0);
end;

The required function is the following:

void keybd_event(BYTE bVirtualKey, BYTE bScanCode, DWORD dwFlags, DWORD dwExtraInfo);

This syntax must be used:

  • bVirtualKey: Virtual Keycode of keys. E.g., VK_RETURN, VK_TAB…
  • bScanCode: Scan Code value of keys. E.g., 0xb8 for “Left Alt” key.
  • dwFlags: Flag that is set for key state. E.g., KEYEVENTF_KEYUP.
  • dwExtraInfo: 32-bit extra information about keystroke.

The following link summarizes all information on the function together in detail: http://www.codeproject.com/Articles/7305/Keyboard-Events-Simulation-using-keybd-event-funct

like image 31
Panschi11291 Avatar answered Sep 29 '22 09:09

Panschi11291