.NET call to send [enter] keystroke into the curre

2020-02-11 09:54发布

问题:

Is there a way to poke the [enter] keystroke into the current process, to force the thread blocking on Console.ReadLine() to exit?

More Info (you can ignore this)

I have a C# console app which is running another thread which is blocking on Console.ReadLine(). As Console.ReadLine calls a native windows thread that runs deep in the bowels of unmanaged code within Windows, it won't abort until it unblocks, and that won't happen until it receives a keypress on the keyboard.

Thus, when I call ".Abort" on this thread, within C# .NET, it won't about until I manually press [enter] on the console. I want to automate this keypress.

回答1:

Use PostMessage to send [enter] into the current process:

    class Program
    {
        [DllImport("User32.Dll", EntryPoint = "PostMessageA")]
        private static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);

        const int VK_RETURN = 0x0D;
        const int WM_KEYDOWN = 0x100;

        static void Main(string[] args)
        {
            Console.Write("Switch focus to another window now to verify this works in a background process.\n");

            ThreadPool.QueueUserWorkItem((o) =>
            {
                Thread.Sleep(4000);

                var hWnd = System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
                PostMessage(hWnd, WM_KEYDOWN, VK_RETURN, 0);
            });

            Console.ReadLine();

            Console.Write("ReadLine() successfully aborted by background thread.\n");
            Console.Write("[any key to exit]");
            Console.ReadKey();
        }
    }

This answer also works around the fact that calling .Abort on ReadLine() won't work in C#, as ReadLine() is running in unmanaged code deep within the Windows kernel.

This answer is superior to any answers that only work if the current process has the focus, such as SendKeys and Input Simulator.



回答2:

http://inputsimulator.codeplex.com/ works just brilliantly in a console app, as long as the current console app has the focus.

Demo code:

InputSimulator.SimulateKeyPress(VirtualKeyCode.RETURN);
Console.Write("[enter] is now queued in the buffer for this console app.\n");
Console.ReadLine();
Console.Write("Program go to here, without the user pressing [enter] on the keyboard.\n");
Console.Write("[any key to exit]\n");
Console.ReadKey();

This code does not work unless the current console app does not have focus, which leads to all sorts of problems with keys getting poked into other 3rd party applications if said console process is designed to run in the background.

See also answer to Interrupt Console.ReadLine, and new accepted answer that involves using PostMessage.



回答3:

Well, you could always use System.Windows.Forms.SendKeys.SendWait(string keyStrokes) to inject the Enter keystroke - this would obviously require a reference to System.Windows.Forms.

However, I would be inclined to question my arcitecture and perhaps use a proper thread waiting mechanism. There are several ways to achieve this - here's an article that I have used before to help in this area : http://www.albahari.com/threading/part2.aspx

Cheers, Chris.