2

我正在制作一个测试控制台应用程序。这个应用程序运行一个void任务(我无法改变这个事实),为了让它保持打开状态,我Console.ReadLine在 Main 方法的末尾插入。

有没有办法消耗从其他线程按下的每个键?我尝试了以下方法,但对 Peek 的调用阻塞了线程。

loop = Task.Run(async () =>
{
    var input = Console.In;
    while (running)
    {
        int key = input.Peek(); // blocks here forever
        if (key == -1)
        {
            await Task.Delay(50);
        }
        else
        {
            input.Read();
            if ((ConsoleKey)key == ConsoleKey.Enter)
            {
                Completed?.Invoke();
            }
            else
            {
                OnKeyDown((ConsoleKey)key);
            }
            // todo how to intercept keyup?
        }
    }
});

这是主要方法

static void Main(string[] args)
{
    GrpcEnvironment.SetLogger(new Grpc.Core.Logging.ConsoleLogger());

    //setup MagicOnion and option.
    var service = MagicOnionEngine.BuildServerServiceDefinition(isReturnExceptionStackTraceInErrorDetail: true);

    var server = new global::Grpc.Core.Server
    {
        Services = { service },
        Ports = { new ServerPort("localhost", 12345, ServerCredentials.Insecure) }
    };

    // launch gRPC Server.
    server.Start();

    // and wait.
    Console.ReadLine();
}

我想要的基本上是在另一个线程上有一个键盘按键事件监听器。


我还尝试了全局键盘挂钩,但这不适用于控制台应用程序。

4

2 回答 2

1

我决定把它而不是放在Console.ReadLineMain 方法的末尾。

while (true) Task.Delay(1000).Wait(); // console.ReadLine doesn't let us to read from console in other threads.

然后我可以做

loop = Task.Run(() =>
{
    while (running)
    {
        var key = Console.ReadKey(true).Key;
        if (key == ConsoleKey.Enter)
        {
            Completed?.Invoke();
        }
        else
        {
            OnKeyDown(key);
        }
        // todo how to intercept keyup?
    }
});

按回车键,我们的应用程序不会关闭,但这是一个测试应用程序,按回车键退出不是我们的要求。

但如果有人仍然知道答案,Console.ReadLine我很感激知道它。

于 2019-01-28T03:09:12.920 回答
1

你认为只是尝试这样的事情?

确保尝试从实际的控制台运行它,因为我在 VS 2017 上的使用在 IDE 中工作的 CTRL-C 上有所不同。(我应该提到这使用 C# 7.2 - 用于异步主)

    class Program
    {
        static async Task Main()
        {
            CancellationTokenSource cts = new CancellationTokenSource();

            Console.CancelKeyPress += (sender, args) => cts.Cancel();

            Console.WriteLine("Press CTRL-C to Exit");

            // Start you server here

            while (!cts.IsCancellationRequested)
            {

                if (Console.KeyAvailable)
                {
                    var key = Console.ReadKey(true);

                    Console.WriteLine($"Read: {key.KeyChar}");
                }

                await Task.Delay(50, cts.Token);
            }
        }
    }
于 2019-01-28T03:30:54.540 回答