Skip to main content
GameDev.net gamedev.net
🔒 Locked

Win32 Keyboard Input Without Delay or Repeat?

Started by dave Jul 4, 2009 at 2:30 PM 30 replies 14.1k views
Original Post
dave
dave
How can i achieve this? I googled and the only thing i found that gave me hope was this but that didnt work. How can i get 'smooth' keyboard input? I remember that i could do it with Direct Input. Ta,
SiCrane
SiCrane
What exactly do you mean by "smooth" keyboard input?
Ximmer
Ximmer
I use

if(GetAsyncKeyState(vkey_here) & 0x8000){    do_stuff}


when I don't want to bother with using DInput
dave
dave
By smooth i mean't without a keyboard delay or repeat.

Thanks,
dave
dave
Quote:
Original post by Ximmer
I use

if(GetAsyncKeyState(vkey_here) & 0x8000){    do_stuff}


when I don't want to bother with using DInput


Sounds like what i'm after, thanks.
MENTAL
MENTAL
Likewise. Not exactly the best way of doing things but it's very simple to setup. Just remember it ignores window focus, so you'll have to test for that separately (i.e. it just reads straight from the keyboard, regardless of whether any of your app windows would actually receive the input).
dave
dave
So how do we solve the problem of when our window doesn't have focus? Is GetAsyncKeyState() the correct way to do it and we just have to check for our focus?
SiCrane
SiCrane
Given that I still have no idea what you mean by delay, I have to ask what's wrong with just processing WM_KEYDOWN?
dave
dave
The keydown repeat delay occurs, ie the delay configurable via the keyboard settings in the control panel. This means you get intervals between WM_KEYDOWN events. Perfectly valid input for typing etc, but polling the state is really what i needed.

Im possibly completely misinterpreting the use of WM_KEYDOWN but i failed to see the answer on MSDN.
iMalc
iMalc
I recommend processing WM_KEYDOWN and WM_KEYUP messages. Works absolutely great for my software 3D renderer.
If you're seeing any kind of delay with this method then post your message pumping loop, as it is probably not written how it should be.
iMalc
iMalc
Quote:
Original post by Dave
The keydown repeat delay occurs, ie the delay configurable via the keyboard settings in the control panel. This means you get intervals between WM_KEYDOWN events. Perfectly valid input for typing etc, but polling the state is really what i needed.

Im possibly completely misinterpreting the use of WM_KEYDOWN but i failed to see the answer on MSDN.
WM_KEYDOWN doesn't do repeats as per the keyboard control panel setting. You only get it when the key is initially pressed and then a WM_KEYUP when you let go, and you simply treat the key as down the whole time between the receiving of the WM_KEYDOWN and WM_KEYUP messages.
You must be processing WM_CHAR messages as well, as those do the keyboard setting repeats.
dave
dave
My message loop is as follows:

	while( WM_QUIT != msg.message )	{		if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )		{			TranslateMessage( &msg );			DispatchMessage( &msg );		}		else		{			MyApplication.Frame();		}	}


I am not handling WM_CHAR.

LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ){	switch( message )	{	case WM_DESTROY:		PostQuitMessage( 0 );		break;	case WM_KEYDOWN:		break;	default:		return DefWindowProc( hWnd, message, wParam, lParam );	}	return 0;}


If i stick a hit count break point on the break line below WM_KEYDOWN and set it to break at 100 hits, it takes about 7 or 8 seconds to get there, when the application framerate is significantly higher than that.
iMalc
iMalc
Quote:
Original post by Dave
My message loop is as follows:

	while( WM_QUIT != msg.message )	{		if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )		{			TranslateMessage( &msg );			DispatchMessage( &msg );		}		else		{			MyApplication.Frame();		}	}


I am not handling WM_CHAR.

LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ){	switch( message )	{	case WM_DESTROY:		PostQuitMessage( 0 );		break;	case WM_KEYDOWN:		break;	default:		return DefWindowProc( hWnd, message, wParam, lParam );	}	return 0;}


If i stick a hit count break point on the break line below WM_KEYDOWN and set it to break at 100 hits, it takes about 7 or 8 seconds to get there, when the application framerate is significantly higher than that.
Well that all looks fine, basically the same as mine in fact.
Sorry, I forgot to say that you should be checking if ((lParam & (1<<30)) == 0)
before handling the WM_KEYDOWN. I just put a when-hit breakpoint in my KeyDown handler and with that check in the message dispatching switch statement before calling the KeyDown handler, it works as I described.
Totally forgot that little if-statement was there.
dave
dave
Yeah that empty case statement was purely for demonstrative purposes. The application class has a wndproc that the events get passed through to, essentially no extra complexity. In regards to the hit count test, how long did it take your hitcount to reach 100?
iMalc
iMalc
Quote:
Original post by Dave
Yeah that empty case statement was purely for demonstrative purposes. The application class has a wndproc that the events get passed through to, essentially no extra complexity. In regards to the hit count test, how long did it take your hitcount to reach 100?
I didn't use a hit counter. There's this really cool feature that not many people seem to know about called "When Hit" breakpoints. You right click on the breakpoint and select "When Hit..." then in the dialog that shows you check the "Print a message" checkbox.
Then have the output window visible while you run your program and you will get the specified output each time it goes through the breakpoint. You can even have it show the values of variables etc. A far better alternative to inserting print statements and rebuilding and running again to debug a problem.
Mine then only shows up the KeyDown handler being called as the key is pressed, which I'm sure you're will too once you add the check I mentioned before. So I would have to press a key 100 times to get to a 100 hitcount.

Just checked MSDN:
Quote:
Because of the autorepeat feature, more than one WM_KEYDOWN message may be posted before a WM_KEYUP message is posted. The previous key state (bit 30) can be used to determine whether the WM_KEYDOWN message indicates the first down transition or a repeated down transition.


LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ){	switch( message )	{	case WM_DESTROY:		PostQuitMessage( 0 );		break;	case WM_KEYDOWN:		if ((lParam & (1<<30)) == 0)			OnKeyDown(wParam); // Put "When Hit" breakpoint on here		break;	default:		return DefWindowProc( hWnd, message, wParam, lParam );	}	return 0;}
dave
dave
Hmm, so as previously said, so long as you keep an app side mapping of the state of the keys (defaulting to up) and assume that when WM_KEYDOWN happens that a key is down until WM_KEYUP is recieved for that key, it should all work.
SiCrane
SiCrane
Quote:
Original post by Dave
The keydown repeat delay occurs, ie the delay configurable via the keyboard settings in the control panel.

That's the repeat part of the question, now WTF did you mean by "without delay and repeat"? What does keyboard delay mean by itself?
iMalc
iMalc
Quote:
Original post by Dave
Hmm, so as previously said, so long as you keep an app side mapping of the state of the keys (defaulting to up) and assume that when WM_KEYDOWN happens that a key is down until WM_KEYUP is recieved for that key, it should all work.
Basically, yeah.
Sik_the_hedgehog
Sik_the_hedgehog
Quote:
Original post by SiCrane
Quote:
Original post by Dave
The keydown repeat delay occurs, ie the delay configurable via the keyboard settings in the control panel.

That's the repeat part of the question, now WTF did you mean by "without delay and repeat"? What does keyboard delay mean by itself?

I think he means the fact that the messages keep being sent. And if there's a delay between the key press and the first message, then he probably isn't polling the window messages fast enough.

What I'd do is just keep track of the buttons you need. WM_KEYDOWN would be used to set the corresponding button into the pressed state, and WM_KEYUP would be used to set the button into the released state. Then you just check the button state. Repeated WM_KEYDOWN messages won't hurt because they'll just set the button into a state it was already.

A similar idea can be applied to WM_INPUT messages.
Don't pay much attention to "the hedgehog" in my nick, it's just because "Sik" was already taken =/ By the way, Sik is pronounced like seek, not like sick.
dave
dave
Quote:
Original post by SiCrane
Quote:
Original post by Dave
The keydown repeat delay occurs, ie the delay configurable via the keyboard settings in the control panel.

That's the repeat part of the question, now WTF did you mean by "without delay and repeat"? What does keyboard delay mean by itself?


Go look in your control panel, change the settings and type and you'll see the difference.

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.