Directly sending keystrokes to another process via hooking

45,323

Solution 1

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);
    }
}
}

Solution 2

You might have to mess around with this but you can send data via process. This might not work for your situation but it is a thought.

using System;
using System.Runtime.InteropServices;
using System.Diagnostics;

    [DllImport("user32.dll", EntryPoint = "FindWindowEx")]
    public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter,          string lpszClass, string lpszWindow);
    [DllImport("User32.dll")]
    public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);

     static void Send(string message)
     {
         Process[] notepads = Process.GetProcessesByName("notepad");

         if (notepads.Length == 0)
             return;

         if (notepads[0] != null)
         {
             IntPtr child = FindWindowEx(notepads[0].MainWindowHandle, 
                 new IntPtr(0), "Edit", null);

             SendMessage(child, 0x000C, 0, message);
         }
     }

If that doesn't work you can always do:

System.Threading.Thread.Sleep(1000);
//User clicks on active form.
System.Windows.Forms.Sendkeys.Sendwait("<Message>");
Share:
45,323
Hydra
Author by

Hydra

Updated on August 23, 2022

Comments

  • Hydra
    Hydra over 1 year

    I'm wondering, after fiddling with all sorts of issues with SendInput, SendKeys, PostMessage, SendMessage, SendNotifyMessage, keybd_event, etc and so forth. To find that well... trying to send a keyboard input to another non-foreground process is quite finicky and unreliable.

    I tried a method of SendInput where I trick the Z-order (to keep the current window on top) and quickly foreground the 3rd party window, send the input, and re-foreground my window. Of which ultimately failed, and also, somehow, not sure why, managed to also proc the keystrokes on my window as well while not foreground (causing an infinite loop of sending and receiving between two windows until I managed to close the process).

    I've tried different combinations of SendMessage and PostMessage. One for down, one for up, as using both for down and up leads to issues, like with PostMessage for both, causing the key to duplicate on the receiving window. or SendMessage for both, which caused issues with text entry, but other functions worked ok. SendMessage for keydown and PostMessage for keyUp worked for all functions, but the reliability rate dropped dramatically, as well as adding latency into key events. Only a combination of PostMessage for keydown, and SendMessage for keyup managed to do anything useful, with a maybe 5-10% fail rate of keyup registering. Same goes for SentNotifyMessage (behaves basically in the same fashion as SendMessage as far as reliability goes).

    So essentially, I'm at whit's end, and I wanted to know about directly injecting a hook into the target window, and doing some voodoo to send keystrokes to it that way, bypassing the message queue etc. Doing so in a way that will not proc global key events, and only affect the target window. Only thing is I'm pretty unknowledgeable when it comes to injecting/hooking, etc. So I turn to you, community.

    Wut do?

  • Hydra
    Hydra about 11 years
    PostMessage worked wonderfully for this. Using Spy++ helped me to structure the messages to look exactly as they did coming from my actual keyboard.
  • FinnTheHuman
    FinnTheHuman about 7 years
    This is exactly what I need. How do I get to know what is lpszClass for my process, though?
  • Derek Johnson
    Derek Johnson about 7 years
    You can use Spy++ to find out what lpClassName is. If lpClassName is NULL, FindWindow finds any window whose title matches the lpWindowName parameter. (msdn.microsoft.com/en-us/library/windows/desktop/…)
  • Sam
    Sam about 7 years
    Just tried this on Windows 10 and it had no effect. Not sure if I've done something wrong or it doesn't work anymore?
  • Victor Chavauty
    Victor Chavauty over 4 years
    I would just like to add that this no longer worked for me. What i had to do was to find the handle for the Edit window, which is a child window of WindowToFind as well as using PostMessage instead of SendMessage. My code ended up being: IntPtr editHandle = (IntPtr)0x00850766; //Found with Spy++ PostMessage(editHandle, 0x100, (IntPtr)0x56, (IntPtr)0);