简体   繁体   中英

C# - trigger key down event for active control

I found command System.Windows.Forms.SendKeys.Send() for sending keypress some key. This function work if open external app like a notepad and set focus and I will be see that my Key printed in this text field. How do same but with key down event, System.Windows.Forms.SendKeys.SendDown("A"); , for example?

I tried call in Timer this command System.Windows.Forms.SendKeys.Send() but have runtime error associated with very fast taped.

You can't use the SendKeys class for that, unfortunately. You will need to go to a lower level API.

Poking a window with a keydown message

In Windows, keyboard events are sent to windows and controls via the Windows message pump. A piece of code using PostMessage should do the trick:

[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);

const uint WM_KEYDOWN = 0x0100;

void SendKeyDownToProcess(string processName, System.Windows.Forms.Keys key)
{
    Process p = Process.GetProcessesByName(processName).FirstOrDefault();
    if (p != null)
    {
        PostMessage(p.MainWindowHandle, WM_KEYDOWN, (int)key, 0);
    }
}

Note that the application receiving these events may not do anything with it until a corresponding WM_KEYUP is received. You can get other message constants from here .

Poking a control other than the main window

The above code will send a keydown to the "MainWindowHandle." If you need to send it to something else (eg the active control) you will need to call PostMessage with a handle other than p.MainWindowHandle . The question is... how do you get that handle?

This is actually very involved... you will need to temporarily attach your thread to the window's message input and poke it to figure out what the handle is. This can only work if the current thread exists in a Windows Forms application and has an active message loop.

An explanation can be found here , as well as this example:

using System.Runtime.InteropServices;

public partial class FormMain : Form
{
    [DllImport("user32.dll")]
    static extern IntPtr GetForegroundWindow();

    [DllImport("user32.dll")]
    static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);

    [DllImport("user32.dll")]
    static extern IntPtr AttachThreadInput(IntPtr idAttach, 
                         IntPtr idAttachTo, bool fAttach);

    [DllImport("user32.dll")]
    static extern IntPtr GetFocus();

    public FormMain()
    {
        InitializeComponent();
    }

    private void timerUpdate_Tick(object sender, EventArgs e)
    {
        labelHandle.Text = "hWnd: " + 
                           FocusedControlInActiveWindow().ToString();
    }

    private IntPtr FocusedControlInActiveWindow()
    {
        IntPtr activeWindowHandle = GetForegroundWindow();

        IntPtr activeWindowThread = 
          GetWindowThreadProcessId(activeWindowHandle, IntPtr.Zero);
        IntPtr thisWindowThread = GetWindowThreadProcessId(this.Handle, IntPtr.Zero);

        AttachThreadInput(activeWindowThread, thisWindowThread, true);
        IntPtr focusedControlHandle = GetFocus();
        AttachThreadInput(activeWindowThread, thisWindowThread, false);

        return focusedControlHandle;
    }
}

The good news-- if SendKeys worked for you, then you might not need to do all this-- SendKeys also sends messages to the main window handle.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM