Directly sending keystrokes to another process via hooking
This is a little code that allows you to send message to a backgrounded application. To send the "A" char for example, simply call sendKeystroke(Keys.A), and don't forget to use namespace System.windows.forms to be able to use the Keys object.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace keybound
{
class WindowHook
{
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
public static void sendKeystroke(ushort k)
{
const uint WM_KEYDOWN = 0x100;
const uint WM_SYSCOMMAND = 0x018;
const uint SC_CLOSE = 0x053;
IntPtr WindowToFind = FindWindow(null, "Untitled1 - Notepad++");
IntPtr result3 = SendMessage(WindowToFind, WM_KEYDOWN, ((IntPtr)k), (IntPtr)0);
//IntPtr result3 = SendMessage(WindowToFind, WM_KEYUP, ((IntPtr)c), (IntPtr)0);
}
}
}
How to send a keystroke to an other process (ex a notepad)?
PostThreadMessage should be used.
hThread = GetWindowThreadProcessId(hwnd,&dwPID);
if (dwPID == dwProcessID && hThread!= NULL ) {
PostThreadMessage( hThread, WM_KEYDOWN,'A',1);
}
Two process must be created by same user. Otherwise, the function fails and returns ERROR_INVALID_THREAD_ID.
If the other process is active window which is capturing keyboard input, SendInput or keybd_event also can be used to send keystroke event.
Is there any way to send key(s) to other application without focus?
I just found the solution.
I didn't know about tab concept. The key point was tab handle, the real handle for key processing. If I use main window handle, it can process WM_CLOSE WM_SETTEXT (also SetWindowText(string)) but not WM_KEYDOWN. I imagined the sequence.
- keyboard stroke
- key event to the handle (main window handle)
- handle gives to received event WM_KEYDOWN / WM_CHAR / WM_KEYUP with VK_*
So I must find the tab handle first.
int getTabHandle() {
int hwnd = 0;
hwnd = FindWindowEx(hwnd , 0, "iexplore.exe", null);
hwnd = FindWindowEx(hwnd , 0, "IEFrame", null);
hwnd = FindWindowEx(hwnd , 0, "Frame Tab", null);
hwnd = FindWindowEx(hwnd , 0, "TabWindowClass", null);
hwnd = FindWindowEx(hwnd , 0, "Shell DocObject View", null);
hwnd = FindWindowEx(hwnd , 0, "Internet Explorer_Server", null);
return hwnd;
}
With this hwnd, I could send key without focus. Thanks.
Sending Keystrokes to Hidden Window via JNA
As stated in the commentary, SendInput
is the most supported.
I tried to use it in the Win32
console and found that it worked very well. The code is as follows.
#include <iostream>
#include <Windows.h>
int main()
{
INPUT input[5];
memset(input, 0, sizeof(input));
input[0].type = input[1].type = input[2].type = input[3].type = input[4].type = INPUT_KEYBOARD;
SetForegroundWindow((HWND)0x000A09D8);//EDIT EDITOR HANDLE
while (1)
{
input[0].ki.wVk = '1';
input[1].ki.wVk = '2';
input[2].ki.wVk = '3';
input[3].ki.wVk = '4';
input[4].ki.wVk = VK_RETURN;
SendInput(5, input, sizeof(INPUT));
std::cout << GetLastError() << std::endl;
Sleep(1000);
input[0].ki.dwFlags = input[1].ki.dwFlags = input[2].ki.dwFlags = input[3].ki.dwFlags = input[4].ki.dwFlags = KEYEVENTF_KEYUP;
SendInput(5, input, sizeof(INPUT));
input[0].ki.dwFlags = input[1].ki.dwFlags = input[2].ki.dwFlags = input[3].ki.dwFlags = input[4].ki.dwFlags = 0;
std::cout << GetLastError() << std::endl;
Sleep(1000);
}
return 0;
}
Send combination of keystrokes to background window
Ok I found a workaround, but it doesn't work for all applications. Otherwise, it works with puTTY, the program I wanted to control with keystroke combination. And it works even if the application isn't focused. So I'm done now!
class SendMessage
{
[DllImport("user32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
public static void sendKeystroke()
{
const uint WM_KEYDOWN = 0x100;
const uint WM_KEYUP = 0x0101;
IntPtr hWnd;
string processName = "putty";
Process[] processList = Process.GetProcesses();
foreach (Process P in processList)
{
if (P.ProcessName.Equals(processName))
{
IntPtr edit = P.MainWindowHandle;
PostMessage(edit, WM_KEYDOWN, (IntPtr)(Keys.Control), IntPtr.Zero);
PostMessage(edit, WM_KEYDOWN, (IntPtr)(Keys.A), IntPtr.Zero);
PostMessage(edit, WM_KEYUP, (IntPtr)(Keys.Control), IntPtr.Zero);
}
}
}
}
Send fast textinput to another process (Window)
First of all, are you intentionally using WM_KEYDOWN (0x0100)
instead of WM_KEYUP (0x0101)
in your SendMessage
example? This would just press the keys, and never release them, so the application would not process them properly.
Another way worth trying would be to send WM_SETTEXT, assuming the control interprets it correctly (like edit controls or combo boxes).
A last option would be to use SendInput which synthesizes keyboard and mouse input on a very low level, but similarly to you keyboard's macro program, this requires you to activate the correct window and set the focus, which can be quite painful.
C# / Send keys combination (CTRL+S) to another window
There is not much point in faking the WM_KEYDOWN/WM_KEYUP
messsages, only send the message they generated. Just the two WM_CHAR
messages.
Please use SendKeys.Send(String) Method instead.
To specify that any combination of SHIFT, CTRL, and ALT should be held
down while several other keys are pressed, enclose the code for those
keys in parentheses. For example, to specify to hold down SHIFT while
E and C are pressed, use "+(EC)". To specify to hold down SHIFT while
E is pressed, followed by C without SHIFT, use "+EC".
The following sample works for me:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Test
{
static class Program
{
[DllImport("user32.dll")]
public static extern int SetForegroundWindow(IntPtr hWnd);
static void Main()
{
Process[] processes = Process.GetProcessesByName("notepad"); //notepad used be test
foreach (Process proc in processes)
{
SetForegroundWindow(proc.MainWindowHandle);
SendKeys.SendWait("^(s)");
}
}
}
}
Related Topics
How to Move Rigidbody Gameobject
Lock-Free Multi-Threading Is for Real Threading Experts
Login Using Google Oauth 2.0 with C#
If My Interface Must Return Task How to Have a No-Operation Implementation
Why Doesn't Mutex Get Released When Disposed
Starting and Stopping Iis Express Programmatically
How to Elegantly Deal with Timezones
Entity Framework Core Using Multiple Dbcontexts
How to Send an Email in .Net According to New Security Policies
How to Make an Installer for My C# Application
Why Is Addrange Faster Than Using a Foreach Loop
How to Sort Depended Objects by Dependency
Mvvm: Binding to Model While Keeping Model in Sync with a Server Version