Check keypress after another keypress in console application (GetAsyncKeyState C#) - c#

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.

Related

Make user press specific key to progress in program

I am currently working on a little lottery console game and wanted to add a "Working" mechanic. I created a new method and want to add multiple tasks where you have to press a specific key like the space bar for example multiple times. So something like this (but actually working):
static void Work()
{
Console.WriteLine("Task 1 - Send analysis to boss");
Console.WriteLine("Press the spacebar 3 times");
Console.ReadKey(spacebar);
Console.ReadKey(spacebar);
Console.ReadKey(spacebar);
Console.WriteLine("Task finished - Good job!");
Console.ReadKey();
}
The Console.ReadKey() method returns a ConsoleKeyInfo structure which gives you all the information you need on which key and modifiers were pressed. You can use this data to filter the input:
void WaitForKey(ConsoleKey key, ConsoleModifiers modifiers = default)
{
while (true)
{
// Get a keypress, do not echo to console
var keyInfo = Console.ReadKey(true);
if (keyInfo.Key == key && keyInfo.Modifiers == modifiers)
return;
}
}
In your use case you'd call that like this:
WaitForKey(ConsoleKey.SpaceBar);
Or you could add a WaitForSpace method that specifically checks for ConsoleKey.SpaceBar with no modifiers.
For more complex keyboard interactions like menus and general input processing you'll want something a bit more capable, but the basic concept is the same: use Console.ReadKey(true) to get input (without displaying the pressed key), check the resultant ConsoleKeyInfo record to determine what was pressed, etc. But for the simple case of waiting for a specific key to be pressed that will do the trick.

ReadKey getting characters pressed before a thread timeout has ended

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;

C# Console application: Console.Readkey() has odd initial skipping behaviour on high framerates

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?

C# - Passively checking for key press

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

GetAsyncKeyState Explanation required

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.

Categories

Resources