Sign in to follow this  

[C++] PeekConsoleInput

This topic is 3592 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey. I've got two functions: one which gets a keypress (removes it from buffer) and returns it and one which returns the (last I hope?) keypress (without removing it from buffer). The only problem is, the second cout statement always prints out: 0 0
#include <windows.h>
#include <iostream>

class Keypress
{
public:
	Keypress() : virtual_key(0), control_key(0) {}
	Keypress(WORD virtual_key, DWORD control_key)
		: virtual_key(virtual_key),	control_key(control_key) {}
	WORD virtual_key;
	DWORD control_key;
};

Keypress get_keypress()
{
	HANDLE input_handle = GetStdHandle(STD_INPUT_HANDLE);
	DWORD events = 0;			// how many events took place
	INPUT_RECORD input_record;	// a record of input events
	DWORD input_size = 1;		// how many characters to read
	bool not_a_keypress = true;
	Keypress keypress;

	do
	{
		// Stop from echoing.
		FlushConsoleInputBuffer(input_handle);
		ReadConsoleInput(input_handle, &input_record, input_size, &events);
		
		if(input_record.EventType == KEY_EVENT && input_record.Event.KeyEvent.bKeyDown)
		{ // A key was pressed, so return it.
			keypress.virtual_key = input_record.Event.KeyEvent.wVirtualKeyCode;
			keypress.control_key = input_record.Event.KeyEvent.dwControlKeyState;
			not_a_keypress = false;
		}
	} while(not_a_keypress);
	// Should not be reached.
	return keypress;
}

Keypress peek_keypress()
{
	HANDLE input_handle = GetStdHandle(STD_INPUT_HANDLE);
	DWORD events = 0;			// how many events took place
	INPUT_RECORD input_record;	// a record of input events
	DWORD input_size = 1;		// how many characters to read

	BOOL peeked = PeekConsoleInput(input_handle, &input_record, input_size, &events);

	Keypress keypress;
	if(peeked && input_record.EventType == KEY_EVENT)
	{ // PeekConsoleInput succeeded and a key was pressed, so set and return keypress.
		keypress.virtual_key = input_record.Event.KeyEvent.wVirtualKeyCode;
		keypress.control_key = input_record.Event.KeyEvent.dwControlKeyState;
	}
	return keypress;
}

int main()
{
	Keypress k;
	Keypress k2;

	while(k.virtual_key != VK_ESCAPE)
	{
		// Get a keypress.
		k = get_keypress();
		// Peek at the last keypress.
		k2 = peek_keypress();

		std::cout << k.virtual_key << " " << k.control_key << std::endl;
		std::cout << k2.virtual_key << " " << k2.control_key << std::endl;
	}
	return 0;
}

When I debug it, this line in peek_keypress has input_record.EventType equaling some junk value like 54248:
if(peeked && input_record.EventType == KEY_EVENT)

Anyone know why this code isn't working? Cheers.

Share this post


Link to post
Share on other sites
Try defining input_record as


INPUT_RECORD input_record[1]




Also, call should be

BOOL peeked = PeekConsoleInput(input_handle, input_record, input_size, &events);



Oh, and use

input_record[0]


when you access members

Share this post


Link to post
Share on other sites
I did what you suggested but nothing changes. I don't think it would matter anyway, since the function still works using just the struct as evidenced by the return value which is 1 for both ReadConsoleInput and PeekConsoleInput when I tested it. Can you think of any other reasons why this might be happening?

Share this post


Link to post
Share on other sites
Quote:
Original post by Mybowlcut
I did what you suggested but nothing changes. I don't think it would matter anyway, since the function still works using just the struct as evidenced by the return value which is 1 for both ReadConsoleInput and PeekConsoleInput when I tested it. Can you think of any other reasons why this might be happening?

Hmm, It could be a timing issue. input_handle may not be ready for you app to process.
Try

DWORD wait = 200;
WaitForSingleObject(input_handle,wait);
BOOL peeked = PeekConsoleInput(input_handle, &input_record, input_size, &events);


You might have to try a different wait too. I'm just going off of MSDN. I don't have a compiler with me now.

Share this post


Link to post
Share on other sites
Hey. I tried that and still no luck. I appreciate your help so far. :) Do you reckon that when you get to a compiler you could try the code sample I posted? That'd be awesome if you could.

Share this post


Link to post
Share on other sites
Quote:
Original post by Mybowlcut
Hey. I tried that and still no luck. I appreciate your help so far. :) Do you reckon that when you get to a compiler you could try the code sample I posted? That'd be awesome if you could.


I think I misunderstood what you're trying to do. What data do you expect the console input buffer to contain for peeking after you've "read" it? Or are you expecting to peek into the buffer before read processes it?



Share this post


Link to post
Share on other sites
I made an interface class called Updateable that returns void and takes no parameters. This means that each class that derives from Updateable needs to be able to get the lass keypress through peek_keypress (because it doesn't have any parameters to use - which is what I prefer). So:

GAME LOOP
GET_KEYPRESS() (USER PRESSES A KEY)
OBJECT.UPDATE() (CALLS PEEK_KEYPRESS)
OBJECT.DRAW()
GAME LOOP

Hope that clears things up.

Share this post


Link to post
Share on other sites
Quote:
Original post by Mybowlcut
I made an interface class called Updateable that returns void and takes no parameters. This means that each class that derives from Updateable needs to be able to get the lass keypress through peek_keypress (because it doesn't have any parameters to use - which is what I prefer). So:

GAME LOOP
GET_KEYPRESS() (USER PRESSES A KEY)
OBJECT.UPDATE() (CALLS PEEK_KEYPRESS)
OBJECT.DRAW()
GAME LOOP

Hope that clears things up.


OK. But..
ReadConsoleInput will wait for an input, process it and remove it from the inputbuffer. What do you expect to be able to Peek in your update function?

If you're simply trying to poll and maintain an input state ( with a one keystroke history? ) you should look into a different scheme for doing so.

You can simply use #PeekConsoleInput to find out how many events are pending to be processed and then process each one of them and maintain an inputstate in your base class which derived classes can access. You can simply use boolean fields for all the keys and update them on key up/down events.

Another way is to use direct input and and use the direct input device state to create a snapshot of the input state each game-loop-frame.

If you're trying to serialize the input.. ignore the above, and just use a queue :D
---
Not sure if thats what you wanted..
- K

Share this post


Link to post
Share on other sites
Ah! Of course! The KeyEvent is removed from the queue so there's nothing to peek! Hmm... I guess that what I wanted to do is have all the objects that need access to input call PeekConsoleInput to get the latest event, and then at the end of the game loop remove the latest event from the queue (once all the objects have called Update()). Is that possible? Is there a function to remove the event from the queue? Should I use ReadConsoleInput for that?

Cheers.

Share this post


Link to post
Share on other sites
Quote:
Original post by Mybowlcut
Ah! Of course! The KeyEvent is removed from the queue so there's nothing to peek! Hmm... I guess that what I wanted to do is have all the objects that need access to input call PeekConsoleInput to get the latest event, and then at the end of the game loop remove the latest event from the queue (once all the objects have called Update()). Is that possible? Is there a function to remove the event from the queue? Should I use ReadConsoleInput for that?
Cheers.

I'm not sure if the console buffer is the right way to proceed. For e.g. if you have multiple key events in the buffer then each object has to know about it before hand and then process each one.

I would probably go with making an input state data structure of 32 or whatever keys and update it each frame. You can either use the app message loop directly if possible w/ your framework or use an external lib. That way each object is de-coupled from the keyboard input mechanism and its easier to make changes. Thats just my .02, Not in anyway the only soln.... ( or even a good one ! :D )

- K

Share this post


Link to post
Share on other sites
Can you give an example of what you mean? Because I can't conceptualise how I'd do it. Perhaps I should just use SDL_Event? That means I'm using an extra DLL or whatever but I guess it would be easier?

Share this post


Link to post
Share on other sites

const int KEY_A = 0;
const int KEY_B = 1;
const int KEY_C = 2;
....
...
//-------------
class Base
{
protected:
bool Keys[256];
public:
void UpdateKeys();
void GameLoop();
virtual void UpdateFrame();
virtual void RenderFrame() { };
virtual void HandleInput() { };
};
//---
void Base :: GameLoop()
{
UpdateFrame();
RenderFrame();
}
//---
void Base :: UpdateFrame ()
{
HandleInput();
// do stuff
}
//---
class Derived : public Base
{
public:
void HandleInput()
{
Base::HandleInput();
if ( Keys[KEY_A] )
{
// do something
}

}
};
//---


Something like this..

#UpdateKeys needs to somehow poll the inputstate and update the Keys array
You could use #SDL_GetKeyState to do that.

Share this post


Link to post
Share on other sites

This topic is 3592 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this