Écouter pour appuyer sur la touche dans l’application de la console .NET

Comment puis-je continuer à exécuter l’application de la console jusqu’à ce que vous appuyiez sur une touche (comme lorsque vous appuyez sur Esc ?)

Je suppose qu’il est enroulé autour d’une boucle while. Je n’aime pas ReadKey car il bloque le fonctionnement et demande une clé, plutôt que de simplement continuer à écouter la touche.

Comment cela peut-il être fait?

Related of "Écouter pour appuyer sur la touche dans l’application de la console .NET"

Utilisez Console.KeyAvailable pour appeler uniquement ReadKey lorsque vous savez qu’il ne bloque pas:

 Console.WriteLine("Press ESC to stop"); do { while (! Console.KeyAvailable) { // Do something } } while (Console.ReadKey(true).Key != ConsoleKey.Escape); 

Vous pouvez modifier légèrement votre approche – utilisez Console.ReadKey() pour arrêter votre application, mais faites votre travail dans un thread d’arrière-plan:

 static void Main(ssortingng[] args) { var myWorker = new MyWorker(); myWorker.DoStuff(); Console.WriteLine("Press any key to stop..."); Console.ReadKey(); } 

Dans la fonction myWorker.DoStuff() , vous myWorker.DoStuff() alors une autre fonction sur un thread d’arrière-plan (utiliser Action<>() ou Func<>() est un moyen facile de le faire), puis retournez immédiatement.

Le plus court chemin:

 Console.WriteLine("Press ESC to stop"); while (!(Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape)) { // do something } 

Console.ReadKey() est une fonction de blocage, elle arrête l’exécution du programme et attend une pression sur une touche, mais grâce à la vérification de Console.KeyAvailable premier, la boucle while n’est pas bloquée, mais s’exécute jusqu’à ce que l’utilisateur appuie sur Esc .

À partir de la malédiction vidéo Construire des applications de console .NET en C # par Jason Roberts sur http://www.pluralsight.com

Nous pourrions faire suite à plusieurs processus en cours d’exécution

  static void Main(ssortingng[] args) { Console.CancelKeyPress += (sender, e) => { Console.WriteLine("Exiting..."); Environment.Exit(0); }; Console.WriteLine("Press ESC to Exit"); var taskKeys = new Task(ReadKeys); var taskProcessFiles = new Task(ProcessFiles); taskKeys.Start(); taskProcessFiles.Start(); var tasks = new[] { taskKeys }; Task.WaitAll(tasks); } private static void ProcessFiles() { var files = Enumerable.Range(1, 100).Select(n => "File" + n + ".txt"); var taskBusy = new Task(BusyIndicator); taskBusy.Start(); foreach (var file in files) { Thread.Sleep(1000); Console.WriteLine("Procesing file {0}", file); } } private static void BusyIndicator() { var busy = new ConsoleBusyIndicator(); busy.UpdateProgress(); } private static void ReadKeys() { ConsoleKeyInfo key = new ConsoleKeyInfo(); while (!Console.KeyAvailable && key.Key != ConsoleKey.Escape) { key = Console.ReadKey(true); switch (key.Key) { case ConsoleKey.UpArrow: Console.WriteLine("UpArrow was pressed"); break; case ConsoleKey.DownArrow: Console.WriteLine("DownArrow was pressed"); break; case ConsoleKey.RightArrow: Console.WriteLine("RightArrow was pressed"); break; case ConsoleKey.LeftArrow: Console.WriteLine("LeftArrow was pressed"); break; case ConsoleKey.Escape: break; default: if (Console.CapsLock && Console.NumberLock) { Console.WriteLine(key.KeyChar); } break; } } } } internal class ConsoleBusyIndicator { int _currentBusySymbol; public char[] BusySymbols { get; set; } public ConsoleBusyIndicator() { BusySymbols = new[] { '|', '/', '-', '\\' }; } public void UpdateProgress() { while (true) { Thread.Sleep(100); var originalX = Console.CursorLeft; var originalY = Console.CursorTop; Console.Write(BusySymbols[_currentBusySymbol]); _currentBusySymbol++; if (_currentBusySymbol == BusySymbols.Length) { _currentBusySymbol = 0; } Console.SetCursorPosition(originalX, originalY); } } 

Voici une approche pour faire quelque chose sur un thread différent et commencer à écouter la touche enfoncée dans un thread différent. Et la console arrêtera son traitement à la fin de votre processus ou lorsque l’utilisateur termine le processus en appuyant sur la touche Échap .

 class SplitAnalyser { public static bool stopProcessor = false; public static bool Terminate = false; static void Main(ssortingng[] args) { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("Split Analyser starts"); Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("Press Esc to quit....."); Thread MainThread = new Thread(new ThreadStart(startProcess)); Thread ConsoleKeyListener = new Thread(new ThreadStart(ListerKeyBoardEvent)); MainThread.Name = "Processor"; ConsoleKeyListener.Name = "KeyListener"; MainThread.Start(); ConsoleKeyListener.Start(); while (true) { if (Terminate) { Console.WriteLine("Terminating Process..."); MainThread.Abort(); ConsoleKeyListener.Abort(); Thread.Sleep(2000); Thread.CurrentThread.Abort(); return; } if (stopProcessor) { Console.WriteLine("Ending Process..."); MainThread.Abort(); ConsoleKeyListener.Abort(); Thread.Sleep(2000); Thread.CurrentThread.Abort(); return; } } } public static void ListerKeyBoardEvent() { do { if (Console.ReadKey(true).Key == ConsoleKey.Escape) { Terminate = true; } } while (true); } public static void startProcess() { int i = 0; while (true) { if (!stopProcessor && !Terminate) { Console.ForegroundColor = ConsoleColor.White; Console.WriteLine("Processing...." + i++); Thread.Sleep(3000); } if(i==10) stopProcessor = true; } } } 

Si vous utilisez Visual Studio, vous pouvez utiliser “Démarrer sans déboguer” dans le menu Déboguer.

Il écrit automatiquement “Appuyez sur n’importe quelle touche pour continuer…” à la console pour vous à la fin de l’application et il laissera la console ouverte pour vous jusqu’à ce que vous appuyez sur une touche.

Traiter les cas que certaines des autres réponses ne se comportent pas bien:

  • Responsive : exécution directe du code de gestion des touches. évite les caprices des délais de vote ou de blocage
  • Optionalité : la pression globale est opt-in ; sinon l’application devrait sortir normalement
  • Séparation des préoccupations : code d’écoute moins invasif; fonctionne indépendamment du code d’application de la console normale.

De nombreuses solutions sur cette page impliquent l’interrogation de Console.KeyAvailable ou le blocage sur Console.ReadKey . S’il est vrai que la Console .NET n’est pas très coopérative, vous pouvez utiliser Task.Run pour évoluer vers un mode d’écoute Async plus moderne.

Le principal problème à prendre en compte est que, par défaut, votre thread de console n’est pas configuré pour un fonctionnement Async – ce qui signifie que lorsque vous quittez le fond de votre fonction main , au lieu d’attendre la fin de Async , votre AppDoman et processus se terminera. Une manière appropriée de résoudre ce problème serait d’utiliser AsyncContext de Stephen Cleary pour établir un support Async complet dans votre programme de console mono-thread. Mais pour des cas plus simples, comme l’attente d’un appui sur une touche, l’installation d’un trampoline complet peut être excessive.

L’exemple ci-dessous serait pour un programme de console utilisé dans une sorte de fichier de commandes itératif. Dans ce cas, lorsque le programme est terminé avec son travail, il devrait normalement quitter sans nécessiter de pression sur une touche, puis nous permettons à une touche facultative d’appuyer sur pour empêcher l’application de quitter. Nous pouvons suspendre le cycle pour examiner des choses, éventuellement reprendre, ou utiliser la pause comme un «sharepoint contrôle» connu pour sortir proprement du fichier de commandes.

 static void Main(Ssortingng[] args) { Console.WriteLine("Press any key to prevent exit..."); var tHold = Task.Run(() => Console.ReadKey(true)); // ... do your console app activity ... if (tHold.IsCompleted) { #if false // For the 'hold' state, you can simply halt forever... Console.WriteLine("Holding."); Thread.Sleep(Timeout.Infinite); #else // ...or allow continuing to exit while (Console.KeyAvailable) Console.ReadKey(true); // flush/consume any extras Console.WriteLine("Holding. Press 'Esc' to exit."); while (Console.ReadKey(true).Key != ConsoleKey.Escape) ; #endif } } 

avec le code ci-dessous, vous pouvez écouter en appuyant sur SpaceBar, au milieu de l’exécution de votre console et faire une pause jusqu’à ce qu’une autre touche soit pressée et écouter EscapeKey pour briser la boucle principale

 static ConsoleKeyInfo cki = new ConsoleKeyInfo(); while(true) { if (WaitOrBreak()) break; //your main code } private static bool WaitOrBreak(){ if (Console.KeyAvailable) cki = Console.ReadKey(true); if (cki.Key == ConsoleKey.Spacebar) { Console.Write("waiting.."); while (Console.KeyAvailable == false) { Thread.Sleep(250);Console.Write("."); } Console.WriteLine(); Console.ReadKey(true); cki = new ConsoleKeyInfo(); } if (cki.Key == ConsoleKey.Escape) return true; return false; } 

Selon mon expérience, dans les applications de console, la manière la plus simple de lire la dernière touche enfoncée est la suivante (exemple avec les touches fléchées):

 ConsoleKey readKey = Console.ReadKey ().Key; if (readKey == ConsoleKey.LeftArrow) {  (); //Do something } else if (readKey == ConsoleKey.RightArrow) {  (); //Do something } 

J’utilise pour éviter les boucles, au lieu de cela j’écris le code ci-dessus dans une méthode, et je l’appelle à la fin de “Method1” et “Method2”, donc après avoir exécuté “Method1” ou “Method2”, Console.ReadKey () .Key est prêt à relire les clés.