Как Console.ReadLine из одного потока и использовать ConsoleKeys из другого потока?
Я делаю тестовое консольное приложение. Это приложение выполняет пустую задачу (я не могу изменить этот факт), и чтобы оно оставалось открытым, я вставляю Console.ReadLine
в конце основного метода.
Есть ли способ использовать каждую нажатую клавишу из других потоков? Я попробовал следующее, но вызов 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();
}
я хочу, чтобы в другом потоке была нажата клавиша прослушивания событий в другом потоке.
Я также попробовал глобальные зацепки клавиатуры, но это не работает для консольного приложения.
2 ответа
Ты думаешь просто попробовать что-то подобное?
Обязательно попробуйте запустить его с реальной консоли, так как мой пробег с VS 2017 варьировался на CTRL-C, работающем в IDE. (Я должен был упомянуть, что это использует 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);
}
}
}
Я решил поставить это вместо Console.ReadLine
в конце основного метода.
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?
}
});
нажав Enter, наше приложение не закроется, но это тестовое приложение, и выход с Enter не является нашим требованием.
но если кто-то еще знает ответ с Console.ReadLine
Я ценю это знать.