Directly Sending Keystrokes to Another Process via Hooking

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.

  1. keyboard stroke
  2. key event to the handle (main window handle)
  3. 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;
}

print

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



Leave a reply



Submit