Reputation: 105
I'm writing a delphi app (myApp) to input keyboard strokes to an external app (extApp).
When extApp launches in windows 7 and I press {tab}{tab}{down} i have the appropriate item in the list box selected. The down arrow selects the second item in the TListBox (WinSpy++ tells me it's a TListBox).
Why then does myApp using this code not have the same functionality as the keyboard? This code will select the TListBox (a result of {tab}{tab} and then NOT move the ListBox selection!
procedure TfrmMain.run;
begin
setForegroundWindow(extApp);
sendTab(extApp);
sendTab(extApp);
sendDown(extApp);
end
procedure TfrmMain.sendTab(h: HWND);
begin
PostMessage(h, WM_KEYDOWN, VK_TAB, 0);
PostMessage(h, WM_KEYUP, VK_TAB, 0);
end;
procedure TfrmMain.sendDown(h:HWND);
begin
PostMessage(h, WM_KEYDOWN, VK_DOWN, 0);
PostMessage(h, WM_KEYUP, VK_DOWN , 0);
end;
Is there a different way I can send a down arrow key stroke to my external app that will mimic the physical keyboard?
Upvotes: 1
Views: 426
Reputation: 595827
You are not setting any of the appropriate state flags in the lParam parameter of the messages. At a minimum, you should be setting the bits for scan codes, previous key states, and transition states, eg:
procedure TfrmMain.sendTab(h: HWND);
var
ScanCode: UINT:
begin
ScanCode := MapVirtualKey(VK_TAB, 0) shl 16;
PostMessage(h, WM_KEYDOWN, VK_TAB, ScanCode);
Sleep(50);
PostMessage(h, WM_KEYUP, VK_TAB, ScanCode or $C0000001);
end;
procedure TfrmMain.sendDown(h:HWND);
var
ScanCode: UINT:
begin
ScanCode := MapVirtualKey(VK_DOWN, 0) shl 16;
PostMessage(h, WM_KEYDOWN, VK_DOWN, ScanCode);
Sleep(50);
PostMessage(h, WM_KEYUP, VK_DOWN, ScanCode or $C0000001);
end;
That being said, you can't simulate keyboard input with PostMessage, so use SendInput()
instead, like Ken White suggested (though you lose the ability to direct the keyboard input to a specific window, it will always go to the foreground window - but then, so does real keyboard input).
Upvotes: 1
Reputation: 125671
The proper way to do so is using SendInput. Something like this should get you started:
var
Inputs: array of TInput;
ScanCode: Word;
begin
ScanCode := MapVirtualKey(VK_TAB, 0);
SetLength(Inputs, 2);
Inputs[0].iType := INPUT_KEYBOARD;
Inputs[0].ki.wVk := VK_TAB;
Inputs[0].ki.wScan := ScanCode;
Inputs[1].iType := INPUT_KEYBOARD;
Inputs[1].ki.wVk := VK_TAB;
Inputs[1].ki.wScan := ScanCode;
Inputs[i].ki.dwFlags := KEYEVENTF_KEYUP;
SendInput(2, Inputs[0], SizeOf(Inputs[0]));
end;
Upvotes: 3