Entrée et sortie simultanées sur la console C #?

J’écris une application serveur et je veux qu’elle soit basée sur la console. J’ai besoin que l’utilisateur puisse entrer différentes commandes, mais il est également possible que quelque chose soit envoyé à la console pendant que l’utilisateur écrit. Cela gâche le tampon. Y a-t-il un moyen propre de faire cela?

Merci.

J’ai commencé à travailler sur un programme de test pour montrer comment diviser la console en une zone de sortie et une zone de saisie, la zone de saisie étant déplacée vers le bas à mesure que la zone de sortie se développe avec davantage de sorties. Ce n’est pas encore parfait, mais vous pourrez peut-être en faire la réponse que vous cherchez:

static int outCol, outRow, outHeight = 10; static void Main(ssortingng[] args) { bool quit = false; System.DateTime dt = DateTime.Now; do { if (Console.KeyAvailable) { if (Console.ReadKey(false).Key == ConsoleKey.Escape) quit = true; } System.Threading.Thread.Sleep(0); if (DateTime.Now.Subtract(dt).TotalSeconds > .1) { dt = DateTime.Now; WriteOut(dt.ToSsortingng(" ss.ff"), false); } } while (!quit); } static void WriteOut(ssortingng msg, bool appendNewLine) { int inCol, inRow; inCol = Console.CursorLeft; inRow = Console.CursorTop; int outLines = getMsgRowCount(outCol, msg) + (appendNewLine?1:0); int outBottom = outRow + outLines; if (outBottom > outHeight) outBottom = outHeight; if (inRow <= outBottom) { int scrollCount = outBottom - inRow + 1; Console.MoveBufferArea(0, inRow, Console.BufferWidth, 1, 0, inRow + scrollCount); inRow += scrollCount; } if (outRow + outLines > outHeight) { int scrollCount = outRow + outLines - outHeight; Console.MoveBufferArea(0, scrollCount, Console.BufferWidth, outHeight - scrollCount, 0, 0); outRow -= scrollCount; Console.SetCursorPosition(outCol, outRow); } Console.SetCursorPosition(outCol, outRow); if (appendNewLine) Console.WriteLine(msg); else Console.Write(msg); outCol = Console.CursorLeft; outRow = Console.CursorTop; Console.SetCursorPosition(inCol, inRow); } static int getMsgRowCount(int startCol, ssortingng msg) { ssortingng[] lines = msg.Split('\n'); int result = 0; foreach (ssortingng line in lines) { result += (startCol + line.Length) / Console.BufferWidth; startCol = 0; } return result + lines.Length - 1; } 

Personnellement, je voudrais utiliser des gestionnaires d’événements pour gérer une console qui gère les entrées et les sorties en même temps, créer une classe ScreenManager ou quoi que ce soit, à l’intérieur de cette classe, append un RunModod () vide, créer un événement avec gestionnaire et variables touche d’entrée “Console.ReadKey (bool) .key”.

 static Consolekey newKey; 

sur votre programme principal, créez une instance de votre classe “comment vous l’avez appelée”, puis créez un fil de cette méthode interne, Thread coreThread = new Thread (delegate () {myinstance.myProgramMrthod ()});

boucle dans votre main jusqu’à ce que les discussions soient en place. tandis que (! Thread.IsAlive);

puis créez la boucle de programme principale.

 while (true) { } 

puis pour safty, joignez votre fil personnalisé afin que le programme principal ne continue pas tant que le fil personnalisé n’est pas fermé / supprimé.

 customThread.Join(); 

vous avez maintenant deux threads fonctionnant séparément.

De retour dans votre classe, créez un commutateur dans votre méthode de gestionnaire d’événements.

 switch (newkey) { case Consolekey.enter Console.WriteLine("enter pressed"); break; ect, ect. default: Console.write(newkey); // writes character key that dont match above conditions to the screen. break; } 

tenez-vous-en à votre logique avec la manière dont vous voulez gérer les clés. Comment utiliser plusieurs touches de modification en C # peut être utile.

Dans la méthode de votre instance, RunProgram () ou quel que soit votre choix, après avoir terminé le code dont vous avez besoin, créez une boucle infinie pour vérifier le changement de clé.

 while (true) { newKey = Console.ReadKey(true).Key; if (newKey != oldKey) { KeyChange.Invoke(); } } 

cette boucle enregistre toutes les touches enfoncées, puis vérifie s’il existe une nouvelle clé, si true déclenche l’événement.

vous avez maintenant le cœur de ce que vous cherchez, une chaîne qui boucle en boucle pour demander une nouvelle clé, tandis que la boucle principale est libre d’afficher le texte que vous souhaitez afficher.

Deux bogues réparables avec ce que je peux penser, un est “par défaut” à l’intérieur du commutateur imprimera à la console en majuscules ou des chaînes. et l’autre est n’importe quel texte ajouté à la console est ajouté au point du curseur afin qu’il ajoute au texte que l’utilisateur vient de saisir.

hwoever je vais, depuis que je viens de le faire, comment vous devez gérer le texte a été ajouté à la console. encore une fois im utilisant un événement. Je pourrais utiliser des méthodes et des fonctions tout au long, mais les événements ajoutent une flexibilité accrue au programme, je pense.

Bon, nous voulons pouvoir append du texte à la console, sans que cela ne perturbe les entrées que nous entrons. garder l’entrée en bas;

créer un nouveau délégué ayant une signature avec un argument de chaîne, void delegate myDelegate (ssortingng Arg). puis créez un événement avec ce délégué, appelez-le newline, newinput, ce que vous aimez.

le gestionnaire d’événements prendra un argument de chaîne (représentant le texte de mise à jour de la console: ce que vous voulez insérer dans la console au-dessus de l’entrée de l’utilisateur), il saisira le texte que l’utilisateur a saisi dans la console, le stockera, puis affichera le paramètre. chaîne sur la console, puis imprimez les informations utilisateur saisies en dessous.

Personnellement, j’ai choisi de créer une chaîne statique en haut à l’extérieur de la méthode, de l’initialiser pour la vider, car elle sera fréquemment utilisée et vous ne voudrez pas créer un nouvel identificateur, puis initialiser la variable à chaque fois que la méthode est appelée. à la fin de la méthode, pour en recréer une nouvelle, encore et encore.

appelez la chaîne “entrée” ou autre chose.

dans la zone par défaut du descripteur d’événement keychange, ajoutez input + = newkey.

dans la console de la console de la section Consolekey.enter, saisissez input puis input = ssortingng.empty ou ssortingng = “”.

dans le gestionnaire d’événements, ajoutez une logique.

 public void OnInsert(ssortingng Argument) { Console.CursorTop -= 1; // moves the cursor to far left so new input overwrites the old. // if arg ssortingng is longer, then print arg ssortingng then print input // ssortingng. if (Argument.Length > input.Length) { Console.WriteLine(Argument); Console.WriteLine(input); } else { // if the users input if longer than the argument text then print // out the argument text, then print white spaces to overwrite the // remaining input characters still displayed on screen. for (int i = 0; i < input.Length;i++ ) { if (i < Argument.Length) { Console.Write(Argument[i]); } else { Console.Write(' '); } } Console.Write(Environment.NewLine); Console.WriteLine(input); } } hope this helps some of you, its not perfect, a quick put together test that works enough to be built on. 

Si vous devez autoriser la sortie pendant que l’utilisateur tape, je vous recommande d’envoyer la sortie dans une nouvelle fenêtre. Ainsi, vous pouvez avoir une fenêtre utilisée pour démarrer l’application, puis créer un thread pour ouvrir une nouvelle console pour l’entrée, puis continuer à envoyer les messages de sortie dans la fenêtre d’origine. Je pense que vous rencontrerez trop de problèmes de locking des ressources si vous essayez de tout conserver dans la même fenêtre.

Ce genre de problème devient un problème un peu plus simple si vous traitez le serveur comme une application client / serveur. Laissez le serveur avoir “n” connexions aux applications admin client qui envoient des commandes et reçoivent la sortie. L’application client peut séparer complètement les entrées et les sorties, en ayant un thread pour gérer les entrées et un autre pour gérer les sorties.

Le thread de sortie peut se bloquer si le thread en entrée est en train d’entrer une ligne et se débloquer lorsque la ligne est annulée ou validée.

Avez-vous essayé d’appeler OpenStandardInput , de lire n’importe quelle entrée et de réinitialiser sa position, puis d’écrire dans le stream de sortie. Ensuite, vous pouvez appeler OpenStandardInput à nouveau et remplir les données dans le stream.

Je pense qu’il n’y a pas de moyen parfait pour accomplir cela. Ce que fait telnet (du moins la dernière version que j’ai utilisée) n’imprime aucune entrée (il suffit de lire les frappes au clavier) et imprime simplement le résultat au fur et à mesure de son arrivée. L’alternative consiste à stocker dans une mémoire tampon toutes les données devant être sorties sur la console et à ne les imprimer que lorsque l’utilisateur a fini d’entrer sa commande. (Vous pouvez même horodater la sortie pour la rendre plus évidente.) Je ne vois vraiment pas de meilleure alternative, car vous allez inévitablement rencontrer des problèmes lors de l’utilisation d’une interface d’E / S synchrone (c’est-à-dire la ligne de commande) avec opérations asynchrones dans le backend.