Click here to Skip to main content
15,885,309 members
Please Sign up or sign in to vote.
5.00/5 (2 votes)
See more:
I am trying to send keys to a background application and I cannot seem to get it to work :(

I can make my application send keys to another application, by making my application bring the other application to the front, but I can't seem to make is send it to a non active window. Could anyone point me in a good direction? I am new to programing with send keys/post message and such so be nice :) Thanks for your help.

Then code I use for sending keys is as follows.

C#
private void button1_Click(object sender, EventArgs e)
{



IntPtr findVulcan = FindWindow(null, GameWindow.Text);
SetForegroundWindow(findVulcan);
Thread.Sleep(1000);
SendKeys.SendWait(Username.Text);
SendKeys.SendWait("{TAB}");
SendKeys.SendWait(Password.Text);
SendKeys.SendWait("{ENTER}");
Thread.Sleep(5000);
SendKeys.SendWait("{ENTER}");
Thread.Sleep(5000);
SendKeys.SendWait("{ENTER}");
Thread.Sleep(5000);
SendKeys.SendWait("{ENTER}");
Posted

Hi Fapsterx,

This should give you an idea. Your problem is: most times you can not send an input to the main window of an application. Most applications use some kind of child-window for editing (a TextBox, whatever).

So you can only send input messages to those. But how to find them? Thats the difficult part, and I dont know the ultimate answer, you have to find it out for every application (you could use tools like spy++)
My code shows the needed steps with notepad as an example.(the edit controls class is "Edit").
It's a complete example just copy to a new console project, add a reference to WindowsForms (or start with a WindowsForms project). (We need the reference here for using the Clipboard class).
Then start notepad and run the code (caution no error handling present!)


C#
using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

namespace SendKeysToAnyApplication
{
    class Program
    {
        delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);

        [DllImport("user32.dll")]
        static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, uint wParam, uint lParam);
        [DllImport("user32.dll")]
        static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
        [DllImport("user32.dll")]
        static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, IntPtr lParam);
        [DllImport("user32.dll")]
        static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

        const uint WM_CHAR = 0x102;
        const uint WM_PASTE = 0x0302;

        static IntPtr m_hWndEdit = IntPtr.Zero;

        [STAThread]
        static void Main(string[] args)
        {
            // for a test we use the notepad window
            // ... so lets have a look if we find an opened notepad window (better you open one first...)
            IntPtr hWnd = FindWindow("Notepad", null);
            // But! we can not send text to the main-window, we have to find the subwindow where the text is entered
            // So lets enumerate all child windows:
            IntPtr hWndEdit = IntPtr.Zero;
            EnumChildWindows(hWnd, EnumChildWindowsCallback, hWndEdit);

            if (m_hWndEdit != null) // edit window found?
            {
                // Now you could use different messages to send text (WM_CHAR, WM_KEYDOWN, ...)
                // I decided to use the clipboard:
                // Copy some text to the clipboard
                Clipboard.SetText("this is magic!");
                // ... and just paste it to the target window
                SendMessage(m_hWndEdit, WM_PASTE, 0, 0);
            }
        }

        static bool EnumChildWindowsCallback(IntPtr hWnd, IntPtr lParam)
        {
            // Search for notepads edit window - if we find it "false" is returned (means stop enumerating windows)

            StringBuilder sb = new StringBuilder();
            GetClassName(hWnd, sb, 256);
            if (!sb.ToString().Contains("Edit"))
            {
                return true;
            }

            m_hWndEdit = hWnd; // Store the handle to notepads edit window (this is the window we want to send the messages to)
            return false;
        }
    }
}
 
Share this answer
 
Comments
NeptuneHACK! 19-Jan-12 15:22pm    
thats about it.
El_Codero 5-Mar-12 18:15pm    
good solution. My 5!
You are calling SendKeys on your own appplication's window. Try to call SendKeys on the window's handle for the window that you are getting with the FindWindow call. :)
 
Share this answer
 
Comments
darkDercane 18-Jan-12 11:42am    
it's a good solution, but will be interesting how we can convert any window
into modal and show it, programatically :P
I'll offer a solution but you are going to need access to the application's code that you are trying to send the message to. If you can't get that you are probably out of luck. But, it is important, I think, to understand why...

Windows has a controller under the hood that polls the keyboard and mouse buffers to determine when the user has provided input. It takes these inputs and turns them into events that it dispatches out to the currently running applications and services (starting with the active application... this is a key point).

Application running in Windows, in turn, each have a main event servicing loop (the message pump). As developers in a higher-level language we don't typically interact with that part of the program but ask a C++ MFC/ATL guy about them... The message pump receives the incoming event messages (which can come from anywhere... not just the Windows controller) in order and processes them, optionally bubbling them up through the application hierarchy via an event. Each component in the tree has the option of consuming the event and setting the completed bit to true and/or passing the event further up the tree. This is how applications execute registered event handlers without the developers having to write any code to interpret the mouse and keyboard events. The message pump handles all of that and just calls the appropriate event handlers.

The problem you have is that the low-level input controller in Windows ASSUMES that all user input is directed to the active window. That is, after all, one of the basic assertions in Windows and is the reason that, for example, if you roll the scroll wheel in a window that isn't active, the active window will scroll rather than the one the mouse is over. (This is different in x-windows, for example, where moving the mouse changes the active window) The SendKeys command sends a message to the low-level Windows input controller which, in turn, sends the message to the active window's message pump. The active window will handle the event and mark the event as complete. That is why when you use SendKeys it will only work with the active window. In your code, you get a handle to the background window but without the call to SetForegroundWindow which makes your target the active window, you are, in reality, sending your keys to whatever window is currently active.

There is, to my knowledge, no way in managed code of directing the windows input controller to send a message to the non-active window nor is there a way to send a message directly to another window's message pump.

So, you could do one of two things...

First, grab a handle to the currently active window, find your background window, make it the active window, send your keys, then make the original active window the active window again (thereby returning the desktop to the original state). The drawback is that with the delays in your code, that operation will be visible and will interrupt whatever the user is doing.

Alternatively, a clean solution is inter-process communications. There are a number of ways to accomplish this but all of them will require your 'target' application to be listening for the messages... via a socket or a named pipe or some other mechanism. That is why I said you need access to the background app's source code... you will have to add this functionality. Hope that is something you'll be able to do.
 
Share this answer
 
Comments
johannesnestler 19-Jan-12 12:29pm    
Reason for bad vote: Your explaination is very nice, but the main point is wrong - I can send messages - have a look at my solution

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900