Sending keystrokes to other *non-focus* application
-
In order to send keystorkes or mouse clicks to other application that is not in focus, I found in the internet the concept of using SendInput while attaching my application thread to the application I want to control. Here is the short console program code for writing the letter 'g' on the notepad program. But still problem - it doesn't put the letter on the notepad... why?
#include "stdafx.h"
#include "conio.h"
#include "windows.h"void sendKey(WORD wVk)
{
INPUT input[2];input\[0\].ki.wVk = wVk; input\[0\].ki.wScan = 0; input\[0\].ki.dwFlags = 0; //press down; input\[0\].ki.time = 0; input\[0\].ki.dwExtraInfo = 0; input\[0\].type = INPUT\_KEYBOARD; input\[1\].ki.wVk = wVk; input\[1\].ki.wScan = 0; input\[1\].ki.dwFlags = KEYEVENTF\_KEYUP; input\[1\].ki.time = 0; input\[1\].ki.dwExtraInfo = 0; input\[1\].type = INPUT\_KEYBOARD; SendInput(2, input, sizeof(INPUT));
}
int _tmain(int argc, _TCHAR* argv[])
{
TCHAR sText[1024];
HWND hTargetWnd;
DWORD processID;
DWORD threadID;HWND hNotepadWnd = FindWindow(NULL, L"Untitled - Notepad"); hTargetWnd=FindWindowEx(hNotepadWnd,NULL,L"Edit",NULL); threadID = GetWindowThreadProcessId(hTargetWnd , &processID); if(hTargetWnd) { wsprintf(sText, L"Target window found\\nWindow = %p\\nprocessID = %x\\nThreadID = %x\\n",hTargetWnd,processID,threadID); wprintf(L"%s",sText); if(AttachThreadInput( GetCurrentThreadId(), threadID,true)) { sendKey('G'); AttachThreadInput(GetCurrentThreadId(),threadID, false); } } else { wprintf(L"Window Notepad wasn't found\\n"); } // if there was SendInput, it also should be seen here while(\_kbhit()) { wprintf(L"%c",getch()); } // wait for keystroke to exit while(!\_kbhit()); return 0;
}
-
In order to send keystorkes or mouse clicks to other application that is not in focus, I found in the internet the concept of using SendInput while attaching my application thread to the application I want to control. Here is the short console program code for writing the letter 'g' on the notepad program. But still problem - it doesn't put the letter on the notepad... why?
#include "stdafx.h"
#include "conio.h"
#include "windows.h"void sendKey(WORD wVk)
{
INPUT input[2];input\[0\].ki.wVk = wVk; input\[0\].ki.wScan = 0; input\[0\].ki.dwFlags = 0; //press down; input\[0\].ki.time = 0; input\[0\].ki.dwExtraInfo = 0; input\[0\].type = INPUT\_KEYBOARD; input\[1\].ki.wVk = wVk; input\[1\].ki.wScan = 0; input\[1\].ki.dwFlags = KEYEVENTF\_KEYUP; input\[1\].ki.time = 0; input\[1\].ki.dwExtraInfo = 0; input\[1\].type = INPUT\_KEYBOARD; SendInput(2, input, sizeof(INPUT));
}
int _tmain(int argc, _TCHAR* argv[])
{
TCHAR sText[1024];
HWND hTargetWnd;
DWORD processID;
DWORD threadID;HWND hNotepadWnd = FindWindow(NULL, L"Untitled - Notepad"); hTargetWnd=FindWindowEx(hNotepadWnd,NULL,L"Edit",NULL); threadID = GetWindowThreadProcessId(hTargetWnd , &processID); if(hTargetWnd) { wsprintf(sText, L"Target window found\\nWindow = %p\\nprocessID = %x\\nThreadID = %x\\n",hTargetWnd,processID,threadID); wprintf(L"%s",sText); if(AttachThreadInput( GetCurrentThreadId(), threadID,true)) { sendKey('G'); AttachThreadInput(GetCurrentThreadId(),threadID, false); } } else { wprintf(L"Window Notepad wasn't found\\n"); } // if there was SendInput, it also should be seen here while(\_kbhit()) { wprintf(L"%c",getch()); } // wait for keystroke to exit while(!\_kbhit()); return 0;
}
keybd_event API is better to use :) refer msdn for more help
Величие не Бога может быть недооценена.
-
In order to send keystorkes or mouse clicks to other application that is not in focus, I found in the internet the concept of using SendInput while attaching my application thread to the application I want to control. Here is the short console program code for writing the letter 'g' on the notepad program. But still problem - it doesn't put the letter on the notepad... why?
#include "stdafx.h"
#include "conio.h"
#include "windows.h"void sendKey(WORD wVk)
{
INPUT input[2];input\[0\].ki.wVk = wVk; input\[0\].ki.wScan = 0; input\[0\].ki.dwFlags = 0; //press down; input\[0\].ki.time = 0; input\[0\].ki.dwExtraInfo = 0; input\[0\].type = INPUT\_KEYBOARD; input\[1\].ki.wVk = wVk; input\[1\].ki.wScan = 0; input\[1\].ki.dwFlags = KEYEVENTF\_KEYUP; input\[1\].ki.time = 0; input\[1\].ki.dwExtraInfo = 0; input\[1\].type = INPUT\_KEYBOARD; SendInput(2, input, sizeof(INPUT));
}
int _tmain(int argc, _TCHAR* argv[])
{
TCHAR sText[1024];
HWND hTargetWnd;
DWORD processID;
DWORD threadID;HWND hNotepadWnd = FindWindow(NULL, L"Untitled - Notepad"); hTargetWnd=FindWindowEx(hNotepadWnd,NULL,L"Edit",NULL); threadID = GetWindowThreadProcessId(hTargetWnd , &processID); if(hTargetWnd) { wsprintf(sText, L"Target window found\\nWindow = %p\\nprocessID = %x\\nThreadID = %x\\n",hTargetWnd,processID,threadID); wprintf(L"%s",sText); if(AttachThreadInput( GetCurrentThreadId(), threadID,true)) { sendKey('G'); AttachThreadInput(GetCurrentThreadId(),threadID, false); } } else { wprintf(L"Window Notepad wasn't found\\n"); } // if there was SendInput, it also should be seen here while(\_kbhit()) { wprintf(L"%c",getch()); } // wait for keystroke to exit while(!\_kbhit()); return 0;
}
audi02 wrote:
But still problem - it doesn't put the letter on the notepad... why?
Functions return values for a reason. Did you bother to check the return value from
SendInput()
?"Old age is like a bank account. You withdraw later in life what you have deposited along the way." - Unknown
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
-
In order to send keystorkes or mouse clicks to other application that is not in focus, I found in the internet the concept of using SendInput while attaching my application thread to the application I want to control. Here is the short console program code for writing the letter 'g' on the notepad program. But still problem - it doesn't put the letter on the notepad... why?
#include "stdafx.h"
#include "conio.h"
#include "windows.h"void sendKey(WORD wVk)
{
INPUT input[2];input\[0\].ki.wVk = wVk; input\[0\].ki.wScan = 0; input\[0\].ki.dwFlags = 0; //press down; input\[0\].ki.time = 0; input\[0\].ki.dwExtraInfo = 0; input\[0\].type = INPUT\_KEYBOARD; input\[1\].ki.wVk = wVk; input\[1\].ki.wScan = 0; input\[1\].ki.dwFlags = KEYEVENTF\_KEYUP; input\[1\].ki.time = 0; input\[1\].ki.dwExtraInfo = 0; input\[1\].type = INPUT\_KEYBOARD; SendInput(2, input, sizeof(INPUT));
}
int _tmain(int argc, _TCHAR* argv[])
{
TCHAR sText[1024];
HWND hTargetWnd;
DWORD processID;
DWORD threadID;HWND hNotepadWnd = FindWindow(NULL, L"Untitled - Notepad"); hTargetWnd=FindWindowEx(hNotepadWnd,NULL,L"Edit",NULL); threadID = GetWindowThreadProcessId(hTargetWnd , &processID); if(hTargetWnd) { wsprintf(sText, L"Target window found\\nWindow = %p\\nprocessID = %x\\nThreadID = %x\\n",hTargetWnd,processID,threadID); wprintf(L"%s",sText); if(AttachThreadInput( GetCurrentThreadId(), threadID,true)) { sendKey('G'); AttachThreadInput(GetCurrentThreadId(),threadID, false); } } else { wprintf(L"Window Notepad wasn't found\\n"); } // if there was SendInput, it also should be seen here while(\_kbhit()) { wprintf(L"%c",getch()); } // wait for keystroke to exit while(!\_kbhit()); return 0;
}
SendInput
andkeybd_event
functions insert keyboard events into the keyboard input stream and these events are received by active/focused window. If You would like to send keystroke to non-focused window You probably should send message directly to that window. -
In order to send keystorkes or mouse clicks to other application that is not in focus, I found in the internet the concept of using SendInput while attaching my application thread to the application I want to control. Here is the short console program code for writing the letter 'g' on the notepad program. But still problem - it doesn't put the letter on the notepad... why?
#include "stdafx.h"
#include "conio.h"
#include "windows.h"void sendKey(WORD wVk)
{
INPUT input[2];input\[0\].ki.wVk = wVk; input\[0\].ki.wScan = 0; input\[0\].ki.dwFlags = 0; //press down; input\[0\].ki.time = 0; input\[0\].ki.dwExtraInfo = 0; input\[0\].type = INPUT\_KEYBOARD; input\[1\].ki.wVk = wVk; input\[1\].ki.wScan = 0; input\[1\].ki.dwFlags = KEYEVENTF\_KEYUP; input\[1\].ki.time = 0; input\[1\].ki.dwExtraInfo = 0; input\[1\].type = INPUT\_KEYBOARD; SendInput(2, input, sizeof(INPUT));
}
int _tmain(int argc, _TCHAR* argv[])
{
TCHAR sText[1024];
HWND hTargetWnd;
DWORD processID;
DWORD threadID;HWND hNotepadWnd = FindWindow(NULL, L"Untitled - Notepad"); hTargetWnd=FindWindowEx(hNotepadWnd,NULL,L"Edit",NULL); threadID = GetWindowThreadProcessId(hTargetWnd , &processID); if(hTargetWnd) { wsprintf(sText, L"Target window found\\nWindow = %p\\nprocessID = %x\\nThreadID = %x\\n",hTargetWnd,processID,threadID); wprintf(L"%s",sText); if(AttachThreadInput( GetCurrentThreadId(), threadID,true)) { sendKey('G'); AttachThreadInput(GetCurrentThreadId(),threadID, false); } } else { wprintf(L"Window Notepad wasn't found\\n"); } // if there was SendInput, it also should be seen here while(\_kbhit()) { wprintf(L"%c",getch()); } // wait for keystroke to exit while(!\_kbhit()); return 0;
}
audi02 wrote:
But still problem - it doesn't put the letter on the notepad... why?
This is by Microsoft design. SendInput[^] and keybd_event[^] inserts keyboard input directly into the kernel input stream. The Windows subsystem Win32k.sys handles user input for usermode windows. Windows that do not have focus do not recieve the WM_KEYDOWN Notification[^], WM_CHAR Notification[^] nor the WM_KEYUP Notification[^]. If you want to send simulated keystrokes to windows that do not have focus you will need to either: 1.) Use the BringWindowToTop Function to bring the window to top before simulating keystrokes. 2.) Use the PostMessage Function[^] to do the dirty work of Win32k.sys This should do the trick:
PostMessage(hTargetWnd,WM_CHAR,'g',0);
Note that using PostMessage to simulate keyboard input is not recommended for a variety of reasons. Some of which include... hooks will not be called... GetKeyState and GetAsyncKeyState will not return correct results... GetQueueStatus with QS_INPUT will not be correct. In a nutshell... by using PostMessage you will be bypassing alot of the Win32k subsystems which could result in undesired behavior. Best Wishes, -David Delaune -
audi02 wrote:
But still problem - it doesn't put the letter on the notepad... why?
Functions return values for a reason. Did you bother to check the return value from
SendInput()
?"Old age is like a bank account. You withdraw later in life what you have deposited along the way." - Unknown
"Fireproof doesn't mean the fire will never come. It means when the fire comes that you will be able to withstand it." - Michael Simmons
-
audi02 wrote:
But still problem - it doesn't put the letter on the notepad... why?
This is by Microsoft design. SendInput[^] and keybd_event[^] inserts keyboard input directly into the kernel input stream. The Windows subsystem Win32k.sys handles user input for usermode windows. Windows that do not have focus do not recieve the WM_KEYDOWN Notification[^], WM_CHAR Notification[^] nor the WM_KEYUP Notification[^]. If you want to send simulated keystrokes to windows that do not have focus you will need to either: 1.) Use the BringWindowToTop Function to bring the window to top before simulating keystrokes. 2.) Use the PostMessage Function[^] to do the dirty work of Win32k.sys This should do the trick:
PostMessage(hTargetWnd,WM_CHAR,'g',0);
Note that using PostMessage to simulate keyboard input is not recommended for a variety of reasons. Some of which include... hooks will not be called... GetKeyState and GetAsyncKeyState will not return correct results... GetQueueStatus with QS_INPUT will not be correct. In a nutshell... by using PostMessage you will be bypassing alot of the Win32k subsystems which could result in undesired behavior. Best Wishes, -David DelauneThanks for the detailed explanation. You are right about the PostMessage as I had tried it. It actually seems to be not practical for me because it seems that I must know what the target program is designed to receive while I only want to send the basic events of mouse and keys. Example: I tried for example to send WM_LBUTTONDOWN in order to simulate left mouse button click, but the target program didn't react to this even it received it. When I checked, using Spy++ the messages it accepts when the mouse is really on it, I found the messages are much more complicated than just WM_LBUTTONDOWN and includes WM_NCHITTEST, WM_SETCURSOR and more. Why it is not just WM_LBUTTONDOWN ? I don't know. it's first time for me in this subject. If you can give some description on this behavior and a solution, that will be great. Maybe I will use the keystrokes simulation through PostMessage and the mouse with other way? Thanks.
-
Thanks for the detailed explanation. You are right about the PostMessage as I had tried it. It actually seems to be not practical for me because it seems that I must know what the target program is designed to receive while I only want to send the basic events of mouse and keys. Example: I tried for example to send WM_LBUTTONDOWN in order to simulate left mouse button click, but the target program didn't react to this even it received it. When I checked, using Spy++ the messages it accepts when the mouse is really on it, I found the messages are much more complicated than just WM_LBUTTONDOWN and includes WM_NCHITTEST, WM_SETCURSOR and more. Why it is not just WM_LBUTTONDOWN ? I don't know. it's first time for me in this subject. If you can give some description on this behavior and a solution, that will be great. Maybe I will use the keystrokes simulation through PostMessage and the mouse with other way? Thanks.
audi02 wrote:
It actually seems to be not practical
Correct. I would say that its not a good idea to use PostMessage for reliably simulating input.
audi02 wrote:
If you can give some description on this behavior and a solution, that will be great.
There are so many things happening in the windows subsystem (Win32k.sys) that it will be difficult to overcome undesired side-effects. For example when the window lost focus Win32k.sys internally keeps track of the window state, the subsystem knows not to put input messages into the window message que. When injecting rogue messages into the que you cannot always predict the outcome. I dont really have any positive advice to give you regarding injecting user input into a window. How do you know the author of notepad or ApplicationX did not check his window state when notepad recieves mouse input? You will also battle these types of issues as well. What type of application are you developing? Why can't you just bring the window to the top? Best Wishes, -David Delaune