WPF C#向外部窗口发送按键失效,求解决方案
The code you’ve written uses WPF’s internal input system (InputManager and KeyEventArgs) to simulate keystrokes. This approach only works within your WPF application—it doesn’t send input to external windows because it’s not interacting with the operating system’s global input queue. WPF’s input processing is isolated to its own UI thread and element tree, so external apps won’t receive those events.
To send keystrokes to external applications, you need to use the Windows API’s SendInput function, which directly interacts with the OS’s input stack. Here’s how to implement this in your WPF app:
First, add the necessary P/Invoke declarations to your static class:
using System; using System.Runtime.InteropServices; using System.Windows.Input; public static class SendKeysHelper { // P/Invoke declarations for Windows API functions [DllImport("user32.dll", SetLastError = true)] private static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize); [DllImport("user32.dll")] private static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll", SetLastError = true)] private static extern bool SetForegroundWindow(IntPtr hWnd); [StructLayout(LayoutKind.Sequential)] private struct INPUT { public uint Type; public InputUnion Data; } [StructLayout(LayoutKind.Explicit)] private struct InputUnion { [FieldOffset(0)] public MOUSEINPUT Mouse; [FieldOffset(0)] public KEYBDINPUT Keyboard; [FieldOffset(0)] public HARDWAREINPUT Hardware; } [StructLayout(LayoutKind.Sequential)] private struct KEYBDINPUT { public ushort Vk; public ushort Scan; public uint Flags; public uint Time; public IntPtr ExtraInfo; } [StructLayout(LayoutKind.Sequential)] private struct MOUSEINPUT { public int X; public int Y; public uint MouseData; public uint Flags; public uint Time; public IntPtr ExtraInfo; } [StructLayout(LayoutKind.Sequential)] private struct HARDWAREINPUT { public uint Msg; public ushort ParamL; public ushort ParamH; } // Constants for keyboard input private const uint INPUT_KEYBOARD = 1; private const uint KEYEVENTF_KEYUP = 0x0002; // Helper to convert WPF Key to Virtual Key code private static ushort GetVirtualKeyCode(Key key) { return (ushort)KeyInterop.VirtualKeyFromKey(key); } public static void SendKey(Key key) { // Convert WPF Key to VK code ushort vkCode = GetVirtualKeyCode(key); if (vkCode == 0) return; // Invalid key // Create input structures for key down and key up INPUT[] inputs = new INPUT[2]; // Key down event inputs[0].Type = INPUT_KEYBOARD; inputs[0].Data.Keyboard.Vk = vkCode; // Key up event inputs[1].Type = INPUT_KEYBOARD; inputs[1].Data.Keyboard.Vk = vkCode; inputs[1].Data.Keyboard.Flags = KEYEVENTF_KEYUP; // Send the input SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT))); } // Optional: Bring target window to foreground before sending keys public static void ActivateWindow(IntPtr windowHandle) { if (GetForegroundWindow() != windowHandle) { SetForegroundWindow(windowHandle); } } }
How to Use:
- Get the handle of the external window you want to send keys to (use
FindWindowfromuser32.dllto get this handle by window title or class name). - Activate the window using
SendKeysHelper.ActivateWindow(windowHandle). - Send the key:
SendKeysHelper.SendKey(Key.A);
If you don’t need full control of SendInput, you can use the SendKeys class from the System.Windows.Forms namespace. Note that you’ll need to add a reference to System.Windows.Forms in your WPF project.
using System.Windows.Forms; using System.Windows.Input; public static class SendKeysHelper { public static void SendKey(Key key) { // Convert WPF Key to the string format expected by SendKeys string keyString = ConvertWpfKeyToSendKeysString(key); if (!string.IsNullOrEmpty(keyString)) { SendKeys.SendWait(keyString); } } private static string ConvertWpfKeyToSendKeysString(Key key) { return key switch { Key.A => "A", Key.B => "B", Key.Enter => "{ENTER}", Key.Back => "{BACKSPACE}", Key.Tab => "{TAB}", Key.Control => "^", Key.Shift => "+", Key.Alt => "%", // Add mappings for other keys as needed _ => null }; } }
Notes:
SendKeys.SendWait()waits for the keystrokes to be processed before returning, ensuring the external app has time to react.- This method is simpler but can be less reliable in edge cases (like with elevated applications or certain input methods).
- Window Activation: Always activate the target window before sending keys—otherwise, keystrokes might go to your WPF app instead.
- Elevated Permissions: If the external app runs as administrator, your WPF app may also need admin rights to send keys to it.
- Modifier Keys: For keys like Shift/Ctrl/Alt, send their down/up events separately or use the special syntax in
SendKeys(e.g.,^Cfor Ctrl+C).
内容的提问来源于stack exchange,提问作者beari7

