i'm attempting my first c# console-based game. I created a centered credits intro with a "press any key to continue..." printed at the end. I used Console.ReadKey() to emulate a pause as it waits for user input. The problem is that you can 'stack' inputs, there is probably a better term but essentially, while the console is in a timeout the key inputs are still read and are queued until the timeout ends.
for example;
//10 second wait
//this is where I would press a key
Thread.Sleep(10000);
char x = Console.ReadKey().KeyChar;
//x will be equal to whatever key I pressed before the timeout
this is not the functionality i'm after. does anyone have a solution to this e.g; not use Thread.Sleep() or Console.ReadKey()
If you still do not understand the question, press a key while the Thread.Sleep() is still in effect and the readkey, after the time is up will print that character. does anyone know how to stop the reading of the key?
If you would like actual project code, just ask. Although I see it as irrelevant for this question.
If you want to clear the buffer before waiting for a key, you can call Console.ReadKey(true) in a loop for as long as there is a KeyAvailable. Passing true to the method specifies that the key should be intercepted and not be output to the console window.
For example:
Thread.Sleep(TimeSpan.FromSeconds(10));
// Clear buffer by "throwing away" any keys that were pressed while we were sleeping
while(Console.KeyAvailable) Console.ReadKey(true);
char x = Console.ReadKey().KeyChar;
Related
I am trying to write a very simple mathematical game in C# Console Application. The program will ask a simple mathematical question to the user. The user must respond by typing the answer and then press enter. I used the code
userinput = Convert.ToInt32(Console.Readline());
code to do this. However, I need the user to assign the value of userinput variable in three seconds after the problem is asked. So, I have to start a countdown timer immediately after the problem is asked. If the user does not type the answer and hit enter within three seconds, the program will display the message "timeout for this question" and immediately display the next question. If the user can type the answer and hit enter within three seconds, the program should immediately stop the countdown timer and evaluate the user's answer. I would be very happy if you can help me with that. Thank you very much in advance.
Note: I read the similar threads but they are based on readykey type user inputs. I need a readline type input.
Some pseudocode:
ask the problem;
start the timer;
if (the user types the answer and presses enter within three seconds)
{
evaluate the answer;
go to the next question;
}
else
{
prompt timeout;
go to the next question;
}
Countdown timers are a great way to add an extra touch of challenge and excitement to any game or activity. In this article, we will provide you with a step-by-step guide on how to set up a countdown timer limit to user input with readline in C# Console.
The first step is to import the C# Console namespace. This will give you access to the readline and Console classes, which are required for setting up a countdown timer. To do this, simply place the following code in your project:
using System;
Next, you need to create a method that will be used to set the timer limit. In this example, we are going to use a loop to count down from the user-specified value to zero. To do this, declare a new integer variable called ‘limit’ and set it to the result of the ReadLine() method. This method will prompt the user to enter a value they want to use as a timer limit:
int limit = int.Parse(Console.ReadLine());
Now, you will need to set up the loop for the countdown. This loop will continue running until it reaches zero. Inside the loop, you can use the Console.WriteLine() method to print out current time left for the user. After each iteration, you need to decrease the value of the limit variable by one:
while (limit > 0)
{
Console.WriteLine("Time left: " + limit);
limit--;
}
Finally, you will need to add some code to print out a message when the timer has reached zero. This can be done by using the Console.WriteLine() method again, this time with a message that informs the user that their time has run out:
if (limit == 0)
{
Console.WriteLine("Time's up!");
}
With that, you have successfully created a countdown timer limit to user input with readline in C# Console! This simple script can be used to add a bit of extra challenge and excitement to any game or activity you create.
I would like to check if the user will make a kepress again after the first one to implement a pause function in a while cycle. The console window is not on focus so I can't use Console.Read()
while (true)
{
if (GetAsyncKeyState(0x21) != 0)
break; //work just fine, if ESC press it exit while
if (GetAsyncKeyState(0x05) != 0)
{
sw.Start();
while (sw.ElapsedMilliseconds < 2000)
{
// if side mouse button is press, it wait 2sec, work just fine
}
sw.Reset();
}
if (GetAsyncKeyState(0x42) != 0)
{
while (GetAsyncKeyState(0x42) == 0)
{
// wait the second B pressing to resume but it dosen't work
}
}
main_function();
}
This code seems to not work, I check GetAsyncKeyState with writeline and it seems that it get the keypressed state for few ms so the pause cicle will end.
I seems that in console c# I can't use ad hoc functions that c# have for forms to check it.
Thanks!
The solution is:
// if pressed the first time
if (GetAsyncKeyState('B'))
{
//if previously detected and still held down
while (!((GetAsyncKeyState('B')) & 0b1000'0000'0001))
{
//wait in here
}
//if key not pressed
while (!GetAsyncKeyState('B'))
{
//wait in here
}
//if you get here, B was pressed, released and pressed again
}
I don't recommend using GetASyncKeyState for anything but quick and simple Proof of Concepts due to the remarks you will read below.
From MSDN:
Return value
Type: SHORT
If the function succeeds, the return value specifies whether the key was pressed since the last call to GetAsyncKeyState, and whether the key is currently up or down. If the most significant bit is set, the key is down, and if the least significant bit is set, the key was pressed after the previous call to GetAsyncKeyState.
Important remarks:
Although the least significant bit of the return value indicates whether the key has been pressed since the last query, due to the pre-emptive multitasking nature of Windows, another application can call GetAsyncKeyState and receive the "recently pressed" bit instead of your application. The behavior of the least significant bit of the return value is retained strictly for compatibility with 16-bit Windows applications (which are non-preemptive) and should not be relied upon.
For the challenge and educational gain, i am currently trying to make a simple game in the console window. I use a very primitive "locked" framerate system as such:
using System.Threading;
// ...
static private void Main(string[] args)
{
AutoResetEvent autoEvent = new AutoResetEvent(false);
Timer timer = new Timer(Update);
timer.Change(0, GameSpeed);
autoEvent.WaitOne();
}
So, a timer ticks every GameSpeed miliseconds, and calls the method Update().
The way that i have understood input in the console window so far is as follows:
The console application has a "queue" where it stores any keyboard input as metadata + an instance of a ConsoleKey enum. The user can add to this queue at any time. If the user holds down, say A, it will add A every computer frame. That is, the actual fastest amount the computer can do, not the locked frames i am working with.
Calling Console.Readkey() will remove and return the first element on this list. Console.KeyAvailable returns a bool indicating whether the list is empty.
If GameSpeedis set to anything higher than 400 everything consistently works fine. The below image displays the results of some Console.WriteLine() debug messages that give the amount of keyboard inputs detected in this locked/custom frame, using the following code:
int counter = 0;
while (Console.KeyAvailable) { counter++; Console.ReadKey(true); }
Console.WriteLine(counter);
Results
I use only the A key. I hold it for some time, then release it again. The GameSpeed is set to 1000. As expected, the first frames give low numbers as i might start pressing half into the frame, and so too with the last frames, as i might release the A early.
Now, the exact same experiment but with a GameSpeed of only 200
As you can see, i've marked the places i begun pressing with yellow. It always, perfectly gets the first frame. But then theres either one, two, or three frames where it acts as if it has gotten no inputs, but then after those frames it's fine and gets around 7 inputs pr frame.
I recognize that you are not supposed to make games in the console window. It is not made for scenarios like this. That does not however eliminate the possibility that there is some specific, logical reason this happens, that i might be able to fix. So, concretely the question is: can anyone provide some knowledge / ideas of why this happens?
If computer specs are needed, just say so in the comments and i'll add them.
Edit:
I think i have found the cause of this error, and it is windows keyboard repeat delay. While you can change this in the control panel, i have searched the web and found no examples of how you would change it in a c# application. The question then boils down to: how do you change windows keyboard repeat delay?
I am not using windows forms so this is not a duplicate of Capture keystroke without focus in console. Please remove the duplicate label or direct me somewhere else
So have been away from C# for a long time and trying to get back into it. I am messing with a small console app that requires inputting text from the user. The whole program works fine but now I want to add a check to see if escape is ever pressed.
I originally used ReadKey, but that just checks the current key which has two problems.
1. it uses the key pressed, so strings are missing a character (the one which was checked)
2. it is only in the moment. I want it to be passively waiting until its pressed
What would be the best way to do this?
ex:
I type the string "Hello World!"
If I press the desired key(lets say escape) at any time, I want it to react. Otherwise the string should be entered like normal
edit
example of made up dictionary program (yes, I know there is already a class for this)
while (Console.ReadKey().Key != ConsoleKey.Escape)
{
string entry = Console.ReadLine();
if (!entry.Contains(","))
{
...
}
else
{
...
}
}
Thank you all very much for your time.
Not sure what you're getting at but you can use this to detect if the Escape key was pressed.
if (Console.KeyAvailable)
if (Console.ReadKey(true).Key == ConsoleKey.Escape)
{
// Do something
}
}
Or alternatively use a loop that breaks when Escape is entered:
var x = Console.ReadKey();
while (x.Key.ToString() != "Escape")
x = Console.ReadKey();
I wanted to make a little keylogger using the console application and I stumbled across this source code on the web and I have trouble understanding it.
while(true)
{
Thread.Sleep(10);
for (int i = 0; i < 255; i++)
{
int keyState = GetAsyncKeyState(i);
if (keyState == -32767)
{
Console.WriteLine((Keys)i);
}
}
}
So from what I understand, keystate is basically a function which tells if a key is currently being pressed. Since we want to check if any of the 255 keyboard keys are being checked we need a for cycle. Correct me if I am wrong.
So if the key we are currently pressing is well... pressed, it will return some Value (Would like to know what value this is...maybe the keycode value? Correct me because I am sure I am wrong).
But the IF is the part where I have totally lost it. If my understanding is correct, then the write line will only happen if we get -32767 which is who knows what? And that is what I would like to know. Why is it -32767? How come it works even if we never get -32767, LMB is 1 for example...?
If my understanding is correct, then the write line will only happen if we get -32767 which is who knows what?
The value of -32767 (0x8001) is an important value. GetAsyncKeyState returns a short, which means it is the least significant bit (0) of the 16bit return value.
According to the docs:
If the function succeeds, the return value specifies whether the key was pressed since the last call to GetAsyncKeyState, and whether the key is currently up or down. If the most significant bit is set, the key is down, and if the least significant bit is set, the key was pressed after the previous call to GetAsyncKeyState.
That means it is looking for a key press between calls.