Sending a keystroke to another application using WinAPI

I need to control another application by sending him keystrokes, such as CTRL S or CTRL SHIFT C or CTRL F.

I tried a lot of things, but I can't get it to work. Therefore, I am trying to do it correctly in a simpler case.

This successfully sends Hey to notepad:

 procedure TForm1.Button1Click(Sender: TObject); var notepad, edit: HWND; begin notepad := FindWindow('notepad', nil); edit := FindWindowEx(notepad, FindWindow('Edit', nil), nil, nil); SendMessage(edit, WM_CHAR, dword('H'), 0); SendMessage(edit, WM_CHAR, dword('e'), 0); SendMessage(edit, WM_CHAR, dword('y'), 0); end; 

And it successfully sends the F5 key to notepad, and also works with F3 , opening the search dialog.

 notepad := FindWindow('notepad', nil); PostMessage(notepad, WM_KEYDOWN, VK_F5, 0); PostMessage(notepad, WM_KEYUP, VK_F5, 0); 

But I do not know why using SendMessage does not work in the example above.

The best I could find is something like this that does nothing.

 notepad := FindWindow('notepad', nil); PostMessage(notepad, WM_KEYDOWN, VK_CONTROL, 0); PostMessage(notepad, WM_KEYDOWN, VkKeyScan('F'), 0); PostMessage(notepad, WM_KEYUP, VkKeyScan('F'), 0); PostMessage(notepad, WM_KEYUP, VK_CONTROL, 0); 

I found somewhere here a library that kind of emulates VBScript key transfer functions, but just looking at the code seems to just pass the keys to the current application or all applications, since there is no Handle parameter.

+4
source share
2 answers

Warning: This method is implementation-specific and should not be used if you need to guarantee the correctness of your program. (On the other hand, you are already on this path. For example, IIRC, in Windows 95 there is not even a Go to dialog.)

I opened notepad.exe in my favorite resource editor and explored the menu bar. I noticed that the Save menu item identifier is 3 . Therefore, the following code executes the Save menu command in notepad:

 var notepad: HWND; begin notepad := FindWindow('notepad', nil); SendMessage(notepad, WM_COMMAND, 3, 0); 

Similarly, Find is 21 in my version of notepad.exe . Go to - 24 .

Update as per comment: If you need to send Ctrl + Key , you can use SendInput :

 var notepad: HWND; inputArray: array[0..3] of TInput; begin notepad := FindWindow('notepad', nil); // TODO: Either exit if notepad isn't focused, or set focus to notepad FillChar(inputArray, length(inputArray) * sizeof(TInput), 0); inputArray[0].Itype := INPUT_KEYBOARD; inputArray[0].ki.wVk := VK_LCONTROL; inputArray[1].Itype := INPUT_KEYBOARD; inputArray[1].ki.wVk := VkKeyScan('S'); inputArray[2].Itype := INPUT_KEYBOARD; inputArray[2].ki.wVk := VkKeyScan('S'); inputArray[2].ki.dwFlags := KEYEVENTF_KEYUP; inputArray[3].Itype := INPUT_KEYBOARD; inputArray[3].ki.wVk := VK_LCONTROL; inputArray[3].ki.dwFlags := KEYEVENTF_KEYUP; SendInput(length(inputArray), inputArray[0], sizeof(TInput)); 
+5
source

I've been using keybd_event for ages. It will always work, even if everything else fails, because it feeds the input directly into the interface between the keyboard driver and Windows. There is no difference between manual entry and key generation using the function below. The only drawback is that the target window should always remain in the foreground.

 procedure SendKey(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; 
+3
source

All Articles