'Write to console while waiting for input

I am a beginner in programming and I need to write a c# console app that does something (let's suppose writes stars to console) in a loop until user inputs a command like "stop". Something like this:

While !('user entered word "stop"'){
    Console.Write("*")
}

The program should write stars independently of any user key presses or other commands, just do it's work until user writes exactly "stop" and presses Enter. This:

string userinput = "";
while (true){
     Console.Write("*");
     userinput = Console.ReadLine();
     if(userinput == "stop"){
         break;
     }
}

is not a solution, because it will keep asking user for the input after each star printed.

Sorry if it's a stupid question, I can't even understand where to start.

EDIT: Okay, it can be another task, like copying files or playing music or whatever, ANYTHING. I just can't understand how to constantly check the console for the entered stop word without asking the user. Console can be blank, waiting for user input.



Solution 1:[1]

This will stop when the user presses any key

        while (!Console.KeyAvailable)
        {
            Console.Write("*");
        }

This will only stop if the user presses Escape:

        while (true)
        {
            Console.Write("*");

            if (Console.KeyAvailable && Console.ReadKey().Key == ConsoleKey.Escape)
            {
                break;
            }
        }

If you want the user to have to type multiple letters (like 'stop') you'll have to read all the keys they press and check whether the last four are 'stop'.

Solution 2:[2]

Where he will write the input if console is used for printing stars in the same moment. You can make a loop to print stars until specific button from the keyboard is not pressed. After that you can make logic to save pressed keys into variable and loop until specific combination is not written. Don't forget to put Sleep in ur loop. Anyway writing stars and writing input in the same time is not a good idea.

Solution 3:[3]

There is a good answer here about reading input while not locking the main thread. You do so using Console.KeyAvailable and Console.ReadKey() in a separate thread.

Writing back to the console at the same time is a little trickier. This would be easier if you let the user type blind (so they can't see what they've typed in). But the problems start when you want to show the user what they have typed, because you have to write the user input back to the console yourself (because you can't use Console.ReadLine() to do it for you). And, I presume, you don't want to end up with stars in the middle of their input, like:

s*****t***o**p

I assume you want something more like:

***********
stop

Which means you need to move the cursor around in the console to write the stars on one line and write the user input on another line.

You should be able to do this with Console.SetCursorPosition to move the cursor up or down a line depending on which line you want to write on. But you will also have to keep track of how many characters you've written on each line so far.

Solution 4:[4]

you can use multi-threading to achieve this. With this, the main thread starts a background thread which will write stars until the person types stop and hits the enter key. It may however effect the way it is displayed since as you are typing, it will look like it is automatically adding the stars to the keys you have pressed but no worries, depending on your timer. When you hit the Enter key, it will not read the stars added previously.

Below is a sample code for you to achieve what you want.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;

    namespace Practice
{
    class Program
    {
        static bool write = true;
        static void Main(string[] args)
        {
            //Write the stars using a background thread
            new Thread(() =>
            {
                Thread.CurrentThread.IsBackground = true;
                WriteStars();
            }).Start();

            while (true)
            {
                //Read the user input
                var input = Console.ReadLine();
                //Check the user input
                if (input.Equals("stop", StringComparison.OrdinalIgnoreCase))
                {
                    write = false;
                    Console.WriteLine("Finished. Program stopped!");
                    Console.ReadKey();
                    break;
                }
            }
        }

        private static void WriteStars()
        {
            while (write)
            {
                Console.Write("*");

                //Make the thread wait for half a second
                Thread.Sleep(500);
            }
        }
    }
}

Thank you

Solution 5:[5]

Here's a pretty high complexity solution. It's not looking for the word "stop", it's just prompting for a string (any string). It would be easy to adapt though.

It polls the keyboard every 250 milliseconds for key input. If two seconds go by with no input, it outputs an asterisk. When you enter a character (or a backspace), it writes out the entire line (padded on the right with spaces), blanking out the existing asterisks.

One thing it doesn't take care of is line wrap. If you let it be for long enough that the line fills with asterisks, then the console with wrap to the second line, and those asterisks will never be blanked out.

I was surprised, but this actually feels like a reasonable UI. I'm not sure it's worth the added complexity, but...

  public static string GetString(string prompt)
  {
      const int pollTime = 250;       //milliseconds
      const int starTime = 8;         //pollTime quantums (in this case 2 * 250 = 2000 ms)
      string buffer = string.Empty;
      Console.Write($"{prompt}: ");
      var top = Console.CursorTop;
      var left = Console.CursorLeft;
      //two loops, 
      //outer loop is per character
      //the inner one causes a star to be output every 2 seconds, 
      //it causes the keyboard to be polled every 1/4 second
      while (true)        //this loop breaks with a return statement
      {
          var noChar = true;
          var starLoopCount = 0;
          while (noChar && starLoopCount < starTime)
          {
              if (Console.KeyAvailable)
              {
                  var keyRead = Console.ReadKey();
                  if (keyRead.Key == ConsoleKey.Enter)
                  {
                      OutputLine(left, top, buffer);
                      return buffer;
                  }

                  if (keyRead.Key == ConsoleKey.Backspace)
                  {
                      if (buffer.Length > 0)
                      {
                          buffer = buffer.Substring(0, buffer.Length - 1);
                          OutputLine(left, top, buffer);
                          noChar = false;
                          continue;
                      }
                  }
                  //otherwise, add the key to the buffer
                  buffer += keyRead.KeyChar;
                  OutputLine(left, top, buffer);
                  noChar = false;
                  starLoopCount = 0;
              }
              ++starLoopCount;
              Thread.Sleep(pollTime);
          }

          if (noChar)
          {
              Console.Write("*");
          }
      }
  }

  private static void OutputLine(int left, int top, string line)
  {
      Console.SetCursorPosition(left, top);
      var blank = new string(' ', 80 - left - line.Length);
      Console.Write(line + blank);
      Console.SetCursorPosition(left + line.Length, top);
  }

Solution 6:[6]

you can use do while loop, and request for a value. for example (if str equals to exit the while loop will end and the loop will end)

string objVal;
string str;
 do {
     Console.WriteLine("Enter a value: ");
     str = Console.ReadLine();
      if (!str.Equals("exit")){ 
          //logic (just an example)
           objVal = str; 
        }
      } while (!str.Equals("exit"));

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Robin Bennett
Solution 2
Solution 3
Solution 4 Conrad
Solution 5 Flydog57
Solution 6