1

I have some code which exits the program when the user types 'q'

//press 'q' to quit application
ConsoleKeyInfo info = Console.ReadKey(true); ;
while (info.KeyChar != 'q') {
    info = Console.ReadKey(true);
}

How do I modify this structure so that there will be a different non-terminating behavior if the captured key is 'p'?

If I change the condition to:

(info.KeyChar != 'q') && (info.KeyChar != 'p')

Then 'p' will also terminate the program. Even if I put logic inside the while loop to handle the 'p' case.

Also:

ConsoleKeyInfo info = Console.ReadKey(true);
while (true) {
    info = Console.ReadKey(true);
    if (info.KeyChar == 'q') break;
    else if (info.KeyChar == 'p') {
        //other behavior
     }
}

Requires the user to press 'q' twice to end the program for some reason, but the intended behavior is that the actions are triggered by one key press.

John Smith
  • 95
  • 5

7 Answers7

3
var exitWhile = false;
while (!exitWhile) {
    ConsoleKeyInfo info = Console.ReadKey(true);
    switch (info.KeyChar) {
        case 'q':
            exitWhile = true;
            break;

        case 'p':
            //something else to do
    }
}
Sam Axe
  • 33,313
  • 9
  • 55
  • 89
1

Because you called ReadKey twice, try this:

while (true) {
    var info = Console.ReadKey(true);
    if (info.KeyChar == 'q') break;
    else if (info.KeyChar == 'p') {
        //other behavior
    }
}
ViVi
  • 4,339
  • 8
  • 29
  • 52
Dr.Haimovitz
  • 1,568
  • 12
  • 16
0

Personally, I'd go with something like this:

ConsoleKeyInfo info;
bool done = false;
while (!done) {
    info = Console.ReadKey(true);
    switch(info.KeyChar) {
        case 'p':
            // do something
            break;
        case 'q':
            done = true;
            // do something else
            break;
    }
}
zerkms
  • 249,484
  • 69
  • 436
  • 539
Sebastian Lenartowicz
  • 4,695
  • 4
  • 28
  • 39
0
do {
   info = Console.ReadKey(true);
   if (info.KeyChar == 'q') break;
   else if (info.KeyChar == 'p') {
    //other behavior
   }
}while (true);
Junaid
  • 583
  • 6
  • 19
0
while (true)
{
    ConsoleKeyInfo info = Console.ReadKey(true);
    {
        if (info.KeyChar == 'q')
            Environment.Exit(0);
        else if (info.KeyChar == 'p')
        {
            //other behavior
        }
    }
}
ViVi
  • 4,339
  • 8
  • 29
  • 52
David BS
  • 1,822
  • 1
  • 19
  • 35
0
ConsoleKeyInfo info = Console.ReadKey(true);
while (info.KeyChar != 'q') {
    if (info.KeyChar != 'p') {
        // handle p case
    }
    info = Console.ReadKey(true);
}
naffarn
  • 526
  • 5
  • 12
0

You could really soup up your program with some code of a more functional programming style. I'm assuming that you want to do some more complex things than just quit, and so am presenting a pattern that would be overkill for more basic scenarios. The gist here is that you should be able to specify all your actions with less code, almost all in one place. And the methods that are run should be descriptive—nearly self-documenting.

// Define a class that can return some basic information about what should happen next
// This only has one property but could be much richer
public class KeyActionResult {
   public KeyActionResult(bool shouldQuit) {
      ShouldQuit = false;
   }
   public bool ShouldQuit { get; }
   // put other return values or information
}

public static class MyProgram {
   // Doing this in advance requires the class to be immutable
   private static KeyActionResult _shouldNotQuit = new KeyActionResult(false);
   private static KeyActionResult _shouldQuit = new KeyActionResult(true);

   // Work up the vocabulary that you want to be able to use
   private static Action<KeyActionResult> KeepLoopingAfter(Action action) =>
      () => {
         action();
         return _shouldNotQuit;
      };

   private static Action<KeyActionResult> QuitAfter(Action action) =>
      () => {
         action();
         return _shouldQuit;
      };

   private Action<KeyActionResult> Quit() => () => _shouldQuit;

   private void DoSomethingComplicated() { /* whatever */ }

With that in place, you can use these to really clean up your code.

   // Bind keys to vocabulary and actions, all in high-signal code
   private static keyActions = new Dictionary<char, Action<KeyActionResult>> {
      ['p'] = KeepLoopingAfter(() =>  Console.WriteLine("You pressed 'p'!")),
      ['d'] = KeepLoopingAfter(DoSomethingComplicated),
      ['q'] = Quit(),
      ['x'] = QuitAfter(() => Console.WriteLine("Delete, then quit!"))
   }
      .AsReadOnly();

   // Run the main decision loop
   public static void Main() {
      bool shouldQuit;
      do {
         ConsoleKeyInfo keyInfo = Console.ReadKey(true);
         Action action;
         if (keyActions.TryGetValue(keyInfo.KeyChar, out action)) {
            shouldQuit = action().ShouldQuit;
         } else {
            shouldQuit = false;
         }
      } while (!shouldQuit)
   }
}

You could start doing some multicast to take this to the next level...

ErikE
  • 48,881
  • 23
  • 151
  • 196