Introduction
This article describes an easy way to simulate keyboard press and release keys to another application. It uses
the SendInput
API for simulating keyboard press and release keys.
To illustrate this technique we will show how to automatically run calc.exe and simulate add x and y and get the result back.
Application Latching
We will run the application using the CreateProcess
API and save the process ID to close it.
void startProcess(DWORD &processPid,char*mProcess)
{
BOOL bWorked;
STARTUPINFO suInfo;
PROCESS_INFORMATION procInfo;
memset (&suInfo, 0, sizeof(suInfo));
suInfo.cb = sizeof(suInfo);
bWorked = ::CreateProcess(mProcess,
NULL,
NULL,
NULL,
FALSE,
NORMAL_PRIORITY_CLASS,
NULL,
NULL,
&suInfo,
&procInfo);
if (procInfo.dwThreadId = NULL)
{
}
processPid = procInfo.dwProcessId;
}
Making the application in foreground
Retrieves a handle to the top-level window whose window name matches the AppName using FindWindow
, then activate the application using SetForegroundWindow
so the Keyboard input is directed to the window .
HWND windowHandle = FindWindow(0, AppName);
if(windowHandle == NULL)
{
return -1;
}
SetForegroundWindow(windowHandle);
Simulate keyboard press and release keys
Using SendChar
, SendInt
, SendText
based on
the SendInput
Windows API, we will simulate keyboard
press and release keys.
INPUT ip;
ip.type = INPUT_KEYBOARD;
ip.ki.wScan = 0;
ip.ki.time = 0;
ip.ki.dwExtraInfo = 0;
ip.ki.wVk = CHAR_ID;
ip.ki.dwFlags = 0;
SendInput(1, &ip, sizeof(INPUT));
ip.ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(1, &ip, sizeof(INPUT));
Simulation sequence
First send x then + then Y and press Enter, then copy the result in Clipboard using Ctrl+C.
SendInt(x);
Sendchar(VK_ADD);
SendInt(y);
Sendchar(VK_RETURN);
PressKey(VK_CONTROL);
Sendchar('C');
ReleseKey(VK_CONTROL);
Retrieve the Result from Clipboard
Using GetClipboardData
, retrieve the result from the Clipboard.
int GetClipboardText(char*ClipboardText)
{
HANDLE clip;
if (OpenClipboard(NULL))
{
clip = GetClipboardData(CF_TEXT);
sprintf(ClipboardText,"%s",clip);
return 0;
}
return -1;
}
Closing the application
Enumerate all windows using the EnumWindowsProc
callback function, passing the PID of the process you started earlier.
void killProcess(DWORD processPid)
{
Sleep(100);
HANDLE ps = OpenProcess( SYNCHRONIZE|PROCESS_TERMINATE,
FALSE, processPid);
EnumWindows(EnumWindowsProc, processPid);
CloseHandle(ps) ;
}
Then in EnumWindowsProc
, send the WM_CLOSE
message to close it.
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam)
{
Sleep(1);
DWORD wndPid;
char Title[1024];
GetWindowThreadProcessId(hwnd, &wndPid);
GetWindowText(hwnd,Title,1024);
if ( wndPid == (DWORD)lParam && strlen(Title) != 0)
{
::PostMessage(hwnd, WM_CLOSE, 0, 0);
return false;
}
else
{
return true;
}
}