I would like to write a small application using c#. When user presses any key, then this program performs a binding key.
For example, I press Q, then my application works with Triple Q.
Thank
You can implement that without timer, like this codes:
static void Main(string[] args)
{
var time = 3;
char myKey = 'q';
// do some things ...
var key = Console.ReadKey().KeyChar;
if (key == myKey)
{
bool ok = true;
for (int count = 0; count < time; count++)
{
key = Console.ReadKey().KeyChar;
if (key != myKey)
{
ok = false;
break;
}
}
if (ok)
{
// do my work
}
else
{
// Do some else works ...
}
}
else
{
// Do some else works ...
}
Console.ReadKey();
}
Related
I am trying to build a countdown timer that if the selected choice is set time, it will open and prompts the user to enter value to set the time. once the user is done in typing the numbers, it must show choices like this
Press S to start: Press P to pause
This is what I am lacking, I do not know what to code to enable to pause the time and to start it.
using System;
namespace time_console
{
class Program
{
static void Main(string[] args)
{
designNumbers Fancy = new designNumbers();
Program mainMenu = new Program();
mainMenu.RunMainMenu();
}
private void RunMainMenu()
{
string prompt = "Welcome to Neil's Countdown Timer. Select an option";
string[] options = { "Set Time", "Exit" };
Menu mainMenu = new Menu(prompt, options);
int selectedIndex = mainMenu.Run();
switch (selectedIndex)
{
case 0:
SetTime();
break;
case 1:
Exit();
break;
}
}
private void SetTime()
{
Console.SetCursorPosition(4, 4);
Console.WriteLine("enter time in minutes:seconds ");
Console.SetCursorPosition(4, 5);
int m = Convert.ToInt32(Console.ReadLine());
Console.SetCursorPosition(4, 6);
int s = Convert.ToInt32(Console.ReadLine());
for (; ; )
{
if (s == 0 && m == 0)
{
Console.WriteLine("\nTime's up!");break;
}
if (s == 0)
{
s = 60;
m--;
}
System.Console.Clear();
Console.SetCursorPosition(4, 7);
Console.WriteLine(m + ":" + s--);
System.Threading.Thread.Sleep(1000);
}
WriteLine("Press M to return to Menu");
ConsoleKey a;
ConsoleKeyInfo b = ReadKey(true);
a = b.Key;
if(a == ConsoleKey.M)
{
RunMainMenu();
}
}
private void Exit()
{
WriteLine("press any key to exit...");
ReadKey(true);
Environment.Exit(0);
}
}
}
Now here is the situation we are in:
getinput:
//things happen here
string typed = Console.ReadLine();
try
if (typed == "com")
{
//things happen here
}
else if (Console.ReadKey(true).Key == (ConsoleKey.F1) + (ConsoleModifiers.Alt))
{
System.Environment.Exit(0);
}
//other else if's happen here
else
{
Console.WriteLine("\n" + typed + " isn't an option.");
goto getInput;
}
}
catch (Exception)
{
}
goto getInput;
what i want to do with this is when i press alt+f1 the program will terminate itself however because the program waits for some input from me to write even with the working version (without the alt part) it wants me to type the things then press enter, which i dont want. how does one handlde this??
static void Main(string[] args)
{
Console.TreatControlCAsInput = true;
var typed = ReadLine();
if (typed == "com")
{
Console.WriteLine("com");
//things happen here
}
//other else if's happen here
else
{
Console.WriteLine("\n" + typed + " isn't an option.");
}
}
public static string ReadLine() {
StringBuilder sb = new StringBuilder();
do
{
ConsoleKeyInfo key = Console.ReadKey();
if ((key.Modifiers & ConsoleModifiers.Alt) != 0)
{
if (key.Key == ConsoleKey.K)
{
Console.WriteLine("killing console");
System.Environment.Exit(0);
}
}
else
{
sb.Append(key.KeyChar);
if (key.KeyChar == '\n'||key.Key==ConsoleKey.Enter)
{
return sb.ToString();
}
}
} while (true);
}
that code will help you with your problem,
just be aware that when you reading a line by char's you will need to handle things like backspace
First of all, please consider using loops instead of goto, as gotos are dangerous. Why? Have a look here: 'Goto' is this bad?
To solve your problem you can use the ConsoleKeyInfo class in combination with the Console.ReadKey() method to get information about single key presses. With this you can check for any key-combination right before adding up the single characters to a string. A working example could look like:
namespace Stackoverflow
{
using System;
class Program
{
public static void Main(string[] args)
{
ConsoleKeyInfo keyInfo = default(ConsoleKeyInfo);
string input = string.Empty;
// loop while condition is true
while (true)
{
// read input character-wise as long as user presses 'Enter' or 'Alt+F1'
while (true)
{
// read a single character and print it to console
keyInfo = Console.ReadKey(false);
// check for close-combination
if (keyInfo.Key == ConsoleKey.F1 && (keyInfo.Modifiers & ConsoleModifiers.Alt) != 0)
{
// program terminates
Environment.Exit(0);
}
// check for enter-press
if (keyInfo.Key == ConsoleKey.Enter)
{
// break out of the loop without adding '\r' to the input string
break;
}
// add up input-string
input += keyInfo.KeyChar;
}
// optional: enter was pressed - add a new line
Console.WriteLine();
// user pressed enter, do something with the input
try
{
if (input == "com")
{
// right option - do something
}
else
{
// wrong option - reset ConsoleKeyInfo + input
Console.WriteLine("\n" + input + " isn't an option.");
keyInfo = default(ConsoleKeyInfo);
input = string.Empty;
continue;
}
}
catch (Exception)
{
// handle exceptions
}
}
}
}
}
I am creating a C# console application that will be performing an infinite process. How can I get the application to "pause" when the user presses the escape key?
Once the user presses the escape key I want the option to either exit the application or continue the loop right where it left off. I don't want any discontinuity in the process. If I press Esc at step 100 I should be able to pick right back up at step 101.
Here is my method so far:
// Runs the infinite loop application
public static void runLoop()
{
int count = 0;
while (Console.ReadKey().Key!= ConsoleKey.Escape)
{
WriteToConsole("Doing stuff.... Loop#" + count.ToString());
for (int step = 0; step <= int.MaxValue; step++ ) {
WriteToConsole("Performing step #" + step.ToString());
if (step == int.MaxValue)
{
step = 0; // Re-set the loop counter
}
}
count++;
}
WriteToConsole("Do you want to exit? y/n");
exitApplication(ReadFromConsole());
}
Is there any way to check for the user input key in a separate thread then pause the infinite loop when the other thread sees an Esc key-press?
To find out if there is a key available in the loop, you can do this:
while (someLoopCondition)
{
//Do lots of work here
if (Console.KeyAvailable)
{
var consoleKey = Console.ReadKey(true); //true keeps the key from
//being displayed in the console
if (consoleKey.Key == ConsoleKey.Escape)
{
//Pause here, ask a question, whatever.
}
}
}
Console.KeyAvailable returns true if there is a key in the input stream ready to read and it is a non-blocking call so it won't pause to wait for input. You can check if the escape key was pressed and pause or do whatever you want if the condition is true.
Ron, big thank you for your answer. Using Console.KeyAvalible was key to finding the exact solution to my issue. Here is what I did to produce the results I was expecting. I needed to add in a few methods to check if the user wants to break the current operation or start a new loop from the beginning.
public static void runUpdater()
{
int count = 0;
while (true)
{
WriteToConsole("Doing stuff.... Loop# " + count.ToString());
for (int step = 0; step <= int.MaxValue; step++)
{
if (!breakCurrentOperation())
{
WriteToConsole("Performing step #" + step.ToString());
if (step == int.MaxValue)
{
step = 0; // Re-set the loop counter
}
}
else
{
break;
}
}
count++;
if (!startNewOperation())
{
// Noop
}
else
{
break;
}
}
WriteToConsole("\nAre you ready to run the database updater again? y/n");
startApplication(ReadFromConsole());
}
public static bool startNewOperation()
{
WriteToConsole("Do you want go back to the main menu or start a new update process? \nType y to start a new update process or n to go to the main menu.");
string input = ReadFromConsole();
if (input == "y" || input == "Y")
{
return false;
}
else if (input == "n" || input == "N")
{
return true; // Noop - Restart the Loop from the begining
}
else
{
WriteToConsole("Error: Input was not recognized. ");
return startNewOperation(); // Recursivly call method untill user enters a logical input
}
}
public static bool breakCurrentOperation()
{
if (Console.KeyAvailable)
{
var consoleKey = Console.ReadKey(true);
if (consoleKey.Key == ConsoleKey.Escape)
{
WriteToConsole("Do you want to stop the current process? \nType s to stop or c to continue.");
string input = Console.ReadLine();
if (input == "c" || input == "C")
{
return false; // Continue
}
else if (input == "s" || input == "S")
{
return true; // Break the loop
}
else
{
WriteToConsole("Error: Input was not recognized, the current process will now continue. Press Esc to stop the operation.");
}
}
}
return false;
}
Here are the results:
Is there any way to detect both Readline and ReadKey, so that in most cases it behaves as a readline, except for some special key inputs that should be detected?
I need some "parallel" implementation to introduce simultaneity.
The code below is synchronous and does not meet my need
while ((line = Console.ReadLine()) != "x")
{
if (line == "BLABLA")
{
//Stuff
}
else
{
//Stuff
}
ConsoleKeyInfo ki = Console.ReadKey(true);
if ((ki.Key == ConsoleKey.V) && (ki.Modifiers == ConsoleModifiers.Control))
{
//Stuff
}
}
Here's a function I just made to do this.
Right now it only handles Backspace, Enter and Esc, but it could easily be modified to handle other keys if you deem them necessary.
// returns null if user pressed Escape, or the contents of the line if they pressed Enter.
private static string ReadLineOrEsc()
{
string retString = "";
int curIndex = 0;
do
{
ConsoleKeyInfo readKeyResult = Console.ReadKey(true);
// handle Esc
if (readKeyResult.Key == ConsoleKey.Escape)
{
Console.WriteLine();
return null;
}
// handle Enter
if (readKeyResult.Key == ConsoleKey.Enter)
{
Console.WriteLine();
return retString;
}
// handle backspace
if (readKeyResult.Key == ConsoleKey.Backspace)
{
if (curIndex > 0)
{
retString = retString.Remove(retString.Length - 1);
Console.Write(readKeyResult.KeyChar);
Console.Write(' ');
Console.Write(readKeyResult.KeyChar);
curIndex--;
}
}
else
// handle all other keypresses
{
retString += readKeyResult.KeyChar;
Console.Write(readKeyResult.KeyChar);
curIndex++;
}
}
while (true);
}
No, not as such. Both methods block until the user enters something on the console. So even if you would find a way to have both run in parallel, it will not be deterministic which one gets the first shot.
There is a (not obvious) similar problem: how to make Console.ReadLine() abort/break after a certain amount of time without user input.
There have been multiple attempts for this problem here:
Console.ReadLine Break
How to add a Timeout to Console.ReadLine()?
Most are modelled around either creating your own version of a ReadLine function that adds a timeout (or in your case special handling for certain character (codes)) or the use some sort of threading.
Both ways are either non-trivial or have their own issues (make sure you review the comments, even for the accepted answers).
In short, I think you will need to roll your own version of ReadLine, based on Console.ReadKey with your special handling included and that much of the genuine Console.ReadLine behavior that you require. Note that this even include such basic things as RETURN, ARROW KEYS, BACKSPACE handling, etc.
Update: There is the getline.cs Code from the Mono project, which implements a line editing capability like it was provided by some venerable UNIX shells (EMACS mode, if you care). For that, I believe it will need to implement some sort of ReadLine replacement, although I haven't checked. Maybe you can use this as a starting point.
Here is a method that I created that works great. You do not have to press button twice in order for string to start appearing. Basically this replaces Console.ReadLine() but it also looks for Esc key pressed. Just look at return type of method if it is null then you know Esc was pressed.
private string ReadLineOrEscape()
{
ConsoleKeyInfo keyInfo = new ConsoleKeyInfo();
StringBuilder sb = new StringBuilder();
int index = 0;
while (keyInfo.Key != ConsoleKey.Enter)
{
keyInfo = Console.ReadKey(true);
if (keyInfo.Key == ConsoleKey.Escape)
{
return null;
}
if(keyInfo.Key == ConsoleKey.Backspace)
{
if (index > 0)
{
Console.CursorLeft = index - 1;
sb.Remove(index - 1, 1);
Console.Write(" \b");
index--;
}
}
if(keyInfo.KeyChar > 31 && keyInfo.KeyChar < 127)
{
index++;
Console.Write(keyInfo.KeyChar);
sb.Append(keyInfo.KeyChar);
}
}
return sb.ToString(); ;
}
In response to #Overlord Zurd, I improved the code provided by the user.
public class ConsoleOutput
{
private ConsoleOutputType OutputType { get; set; }
private object MyObject { get; }
private static bool IsInserting { get; set; }
public string KeyName => IsKey() && (ConsoleKeyInfo)MyObject != null ? ((ConsoleKeyInfo)MyObject).Key.ToString() : "Null";
public string OutputString => !IsKey() && MyObject != null ? (string)MyObject : string.Empty;
public static event Action<string> ReadInput = delegate { };
public static event Action<ConsoleKeyInfo> ReadKey = delegate { };
private ConsoleOutput()
{
}
public ConsoleOutput(object obj)
{
MyObject = obj;
OutputType = obj is ConsoleKeyInfo ? ConsoleOutputType.Key : ConsoleOutputType.Value;
}
public bool IsKey()
{
return OutputType == ConsoleOutputType.Key;
}
public bool IsExitKey()
{
if (!IsKey())
return false;
var info = ((ConsoleKeyInfo)MyObject);
return (info.Modifiers & ConsoleModifiers.Control) != 0 && info.Key == ConsoleKey.B;
}
public string GetValue()
{
return (string)MyObject;
}
// returns null if user pressed Escape, or the contents of the line if they pressed Enter.
public static ConsoleOutput ReadLineOrKey()
{
string retString = "";
int curIndex = 0;
do
{
ConsoleKeyInfo readKeyResult = Console.ReadKey(true);
// handle Enter
if (readKeyResult.Key == ConsoleKey.Enter)
{
ReadInput?.Invoke(retString);
Console.WriteLine();
return new ConsoleOutput(retString);
}
// handle backspace
if (readKeyResult.Key == ConsoleKey.Backspace)
{
if (curIndex > 0)
{
retString = retString.Remove(retString.Length - 1);
Console.Write(readKeyResult.KeyChar);
Console.Write(' ');
Console.Write(readKeyResult.KeyChar);
--curIndex;
}
}
else if (readKeyResult.Key == ConsoleKey.Delete)
{
if (retString.Length - curIndex > 0)
{
// Store current position
int curLeftPos = Console.CursorLeft;
// Redraw string
for (int i = curIndex + 1; i < retString.Length; ++i)
Console.Write(retString[i]);
// Remove last repeated char
Console.Write(' ');
// Restore position
Console.SetCursorPosition(curLeftPos, Console.CursorTop);
// Remove string
retString = retString.Remove(curIndex, 1);
}
}
else if (readKeyResult.Key == ConsoleKey.RightArrow)
{
if (curIndex < retString.Length)
{
++Console.CursorLeft;
++curIndex;
}
}
else if (readKeyResult.Key == ConsoleKey.LeftArrow)
{
if (curIndex > 0)
{
--Console.CursorLeft;
--curIndex;
}
}
else if (readKeyResult.Key == ConsoleKey.Insert)
{
IsInserting = !IsInserting;
}
#if DEBUG
else if (readKeyResult.Key == ConsoleKey.UpArrow)
{
if (Console.CursorTop > 0)
--Console.CursorTop;
}
else if (readKeyResult.Key == ConsoleKey.DownArrow)
{
if (Console.CursorTop < Console.BufferHeight - 1)
++Console.CursorTop;
}
#endif
else
// handle all other keypresses
{
if (IsInserting || curIndex == retString.Length)
{
retString += readKeyResult.KeyChar;
Console.Write(readKeyResult.KeyChar);
++curIndex;
}
else
{
// Store char
char c = readKeyResult.KeyChar;
// Write char at position
Console.Write(c);
// Store cursor position
int curLeftPos = Console.CursorLeft;
// Clear console from curIndex to end
for (int i = curIndex; i < retString.Length; ++i)
Console.Write(' ');
// Go back
Console.SetCursorPosition(curLeftPos, Console.CursorTop);
// Write the chars from curIndex to end (with the new appended char)
for (int i = curIndex; i < retString.Length; ++i)
Console.Write(retString[i]);
// Restore again
Console.SetCursorPosition(curLeftPos, Console.CursorTop);
// Store in the string
retString = retString.Insert(curIndex, new string(c, 1));
// Sum one to the cur index (we appended one char)
++curIndex;
}
}
if (char.IsControl(readKeyResult.KeyChar) &&
readKeyResult.Key != ConsoleKey.Enter &&
readKeyResult.Key != ConsoleKey.Backspace &&
readKeyResult.Key != ConsoleKey.Tab &&
readKeyResult.Key != ConsoleKey.Delete &&
readKeyResult.Key != ConsoleKey.RightArrow &&
readKeyResult.Key != ConsoleKey.LeftArrow &&
readKeyResult.Key != ConsoleKey.Insert)
{
#if DEBUG
if (readKeyResult.Key == ConsoleKey.UpArrow || readKeyResult.Key == ConsoleKey.DownArrow)
continue;
#endif
ReadKey?.Invoke(readKeyResult);
Console.WriteLine();
return new ConsoleOutput(readKeyResult);
}
}
while (true);
}
}
As you can see, I implemented Insert, Arrow control, Delete, etc etc... (Insert was an important thing because if you write any text with this code you will see behavior as Insert key provides).
And example of use:
internal class Program
{
private static void Main(string[] args)
{
Console.Write("Write test string: ");
var test = ConsoleOutput.ReadLineOrKey();
if (test.IsKey())
Console.WriteLine(test.KeyName);
else
Console.WriteLine($"Output string: {test.OutputString}");
Console.Read();
}
}
You can keep updated on this link (is a link to my lib I'm currently working at).
Talking console here.
The idea is that if user presses any key except numbers(the ones above the letter keys, and numpad) during an input prompt in the console, then nothing will be typed. Its's as if console will ignore any non-numeric key presses.
How would one do it the right way?
Try the ReadKey method:
while (processing input)
{
ConsoleKeyInfo input_info = Console.ReadKey (true); // true stops echoing
char input = input_info.KeyChar;
if (char.IsDigit (input))
{
Console.Write (input);
// and any processing you may want to do with the input
}
}
private static void Main(string[] args) {
bool inputComplete = false;
System.Text.StringBuilder sb = new System.Text.StringBuilder();
while (!inputComplete ) {
System.ConsoleKeyInfo key = System.Console.ReadKey(true);
if (key.Key == System.ConsoleKey.Enter ) {
inputComplete = true;
}
else if (char.IsDigit(key.KeyChar)) {
sb.Append(key.KeyChar);
System.Console.Write(key.KeyChar.ToString());
}
}
System.Console.WriteLine();
System.Console.WriteLine(sb.ToString() + " was entered");
}
This little experiment works like that:
static void Main()
{
while (true)
{
var key = Console.ReadKey(true);
int i;
if (int.TryParse(key.KeyChar.ToString(), out i))
{
Console.Write(key.KeyChar);
}
}
}