Пишите в консоль, ожидая ввода - PullRequest
0 голосов
/ 16 ноября 2018

Я новичок в программировании, и мне нужно написать консольное приложение на c #, которое делает что-то (допустим, записывает звездочки в консоль) в цикле, пока пользователь не введет команду типа «стоп». Примерно так:

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

Программа должна писать звездочки независимо от нажатия клавиш пользователя или других команд, просто делайте это до тех пор, пока пользователь не напишет точно «стоп» и не нажмет Enter. Это:

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

не является решением, потому что он будет продолжать запрашивать у пользователя ввод после каждой напечатанной звезды.

Извините, если это глупый вопрос, я даже не могу понять, с чего начать.

EDIT: Хорошо, это может быть другая задача, например, копирование файлов или воспроизведение музыки или что-то еще, НИЧЕГО. Я просто не могу понять, как постоянно проверять консоль на наличие введено стоп-слово без запроса пользователя. Консоль может быть пустой, ожидая ввода пользователя.

Ответы [ 5 ]

0 голосов
/ 16 ноября 2018

Вот довольно сложное решение. Оно не ищет слово «стоп», оно просто запрашивает строку (любую строку). Хотя было бы легко адаптироваться.

Опрашивает клавиатуру каждые 250 миллисекунд для клавишного ввода. Если две секунды проходят без ввода, выводится звездочка. Когда вы вводите символ (или клавишу возврата), он записывает всю строку (дополненную справа пробелами), убирая существующие звездочки.

Одна вещь, о которой она не заботится, это перенос строки. Если вы позволите этому быть достаточно долго, чтобы строка заполнилась звездочками, то консоль с переносом на вторую строку, и эти звездочки никогда не будут убраны.

Я был удивлен, но на самом деле это похоже на разумный интерфейс. Я не уверен, что это стоит дополнительной сложности, но ...

  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);
  }
0 голосов
/ 16 ноября 2018

вы можете использовать многопоточность для достижения этой цели. При этом основной поток запускает фоновый поток, который будет писать звезды, пока человек не напечатает остановку и не нажмет клавишу ввода. Однако это может повлиять на то, как оно отображается, поскольку во время набора текста будет выглядеть, как будто оно автоматически добавляет звезды к нажатым клавишам, но не беспокоится, в зависимости от вашего таймера. Когда вы нажимаете клавишу Enter, он не будет читать ранее добавленные звезды.

Ниже приведен пример кода для достижения желаемого.

    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);
            }
        }
    }
}

Спасибо

0 голосов
/ 16 ноября 2018

Это остановится, когда пользователь нажмет любую клавишу

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

Это остановится, только если пользователь нажмет Escape:

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

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

Если вы хотите, чтобы пользователь вводил несколькобуквы (например, «стоп»), вам нужно прочитать все клавиши, которые они нажимают, и проверить, являются ли последние четыре «стопами».

0 голосов
/ 16 ноября 2018

Здесь хороший ответ о чтении ввода без блокировки основного потока. Вы делаете это, используя Console.KeyAvailable и Console.ReadKey() в отдельном потоке.

Одновременная запись на консоль немного сложнее. Это было бы проще, если бы вы позволили пользователю печатать вслепую (чтобы он не мог видеть, что набрал). Но проблемы начинаются, когда вы хотите, чтобы показал пользователю, что он набрал , потому что вы должны сами записать ввод пользователя в консоль (потому что вы не можете использовать Console.ReadLine(), чтобы сделать это за вас. ). И, я полагаю, вы не хотите, чтобы в конце их ввода появлялись звезды, например:

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

Полагаю, вы хотите что-то похожее на:

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

Это означает, что вам нужно переместить курсор в консоли, чтобы написать звездочки на одной строке и записать пользовательский ввод на другой строке.

Вы можете сделать это с помощью Console.SetCursorPosition, чтобы переместить курсор вверх или вниз на строку в зависимости от того, на какой строке вы хотите писать. Но вам также придется отслеживать, сколько символов вы написали в каждой строке.

0 голосов
/ 16 ноября 2018

Где он запишет ввод, если консоль используется для печати звезд в тот же момент. Вы можете сделать цикл для печати звездочек, пока не нажмете определенную кнопку на клавиатуре. После этого вы можете создать логику для сохранения нажатых клавиш в переменной и цикле, пока не будет записана конкретная комбинация. Не забудьте поставить Sleep в вашу петлю. В любом случае, написание звезд и ввод данных одновременно - не очень хорошая идея.

...