Sign in to follow this  
jagguy

key press overload

Recommended Posts

When I have a function to test a key press and count the amount of loops it goes through with each key press I get a huge number. In a directX prog with regular loop calling render(). If I touch the left key I get about 50 -100 clocked up on a simple counter at a time and not 1. This is making it impossible to see if a key press has been hit. render() { .... action=moveMap(); static int yt=0; if (action==4) { startRow+=1; endRow+=1; yt++; action=0; } ----- int moveMap() { if (GetAsyncKeyState(VK_LEFT) ) { //MessageBox(0, fps33, fps33, MB_OK); return 4; } ---- If I press the left key once only I will get the counter variable 'yt'= same huge number and not '1'.

Share this post


Link to post
Share on other sites
That must be after your loop has run 50-100 times, no? GetAsyncKey will just return whether the key is pressed at the specific time you call it, and will not "reset" or anything to detect a single key press.

Easiest way round this (if I am correct) would be to have a lock variable that is set to true when the key press is first detected, then test to see if the
key is NOT pressed and clear the lock. Only act on the keypress when the key is
down and the lock is false.

render()
{
....

action=moveMap();
bool KeyLock=false;
static int yt=0;
if (action==4 && !KeyLock)
{
startRow+=1;
endRow+=1;
yt++;
action=0;
}
-----
int moveMap()
{
if (GetAsyncKeyState(VK_LEFT) )
{
//MessageBox(0, fps33, fps33, MB_OK);
KeyLock=true;
return 4;
}
else KeyLock=false;
}

Share this post


Link to post
Share on other sites
While you where pressing the left key you went through the loop a great number of times.
You should set flags, instead of increments.
Or maybe your print function prints a pointer instead of a value.

this should work, didn't test it though

render()
{
static int yt=0;
static int yflag=0;
int state = GetAsyncKeyState(VK_LEFT);

if (state && yflag==0)
{
yflag=1;
startRow+=1;
endRow+=1;
yt++;
printf("yt: %d",yt);
}
else if (!state && yflag==1)
{
yflag=0;
}
}

Share this post


Link to post
Share on other sites
A simpler way would be to handle the WM_KEYPRESS (as opposed to WM_KEYDOWN and WM_KEYUP) message in your WndProc. This makes Windows take care of all the garbage above, plus key repeats a la your favourite text editor.

I've never really used all this GetAsyncKeyState stuff, although I may now in the future. I tend to have a bool Keys[256]={ false }; global (boo hiss) that I update by responding to WM_KEYUP and WM_KEYDOWN. I can then just consult:

if(Keys[VK_RETURN]) DoTheBusiness();

I'd still have to implement a flag lock system like above though.

Share this post


Link to post
Share on other sites
A simpler way would be to handle the WM_KEYPRESS (as opposed to WM_KEYDOWN and WM_KEYUP) message in your WndProc. This makes Windows take care of all the garbage above, plus key repeats a la your favourite text editor.

I've never really used all this GetAsyncKeyState stuff, although I may now in the future. I tend to have a bool Keys[256]={ false }; global (boo hiss) that I update by responding to WM_KEYUP and WM_KEYDOWN. I can then just consult:

if(Keys[VK_RETURN]) DoTheBusiness();

I'd still have to implement a flag lock system like above though if I wanted to just respond to single key presses.

Share this post


Link to post
Share on other sites
Quote:
Original post by Limitz
While you where pressing the left key you went through the loop a great number of times.
You should set flags, instead of increments.
Or maybe your print function prints a pointer instead of a value.

this should work, didn't test it though

render()
{
static int yt=0;
static int yflag=0;
int state = GetAsyncKeyState(VK_LEFT);

if (state && yflag==0)
{
yflag=1;
startRow+=1;
endRow+=1;
yt++;
printf("yt: %d",yt);
}
else if (!state && yflag==1)
{
yflag=0;
}
}


ok this works. Now just to be fussy, I needed the press to tick over when holding down the key instead of a whole key press for a move. Like moving in a map with just holding down the key.
Maybe I need a timer on the keypress instead.

Share this post


Link to post
Share on other sites
Quote:
Original post by jagguy
Quote:
Original post by Limitz
While you where pressing the left key you went through the loop a great number of times.
You should set flags, instead of increments.
Or maybe your print function prints a pointer instead of a value.

this should work, didn't test it though

render()
{
static int yt=0;
static int yflag=0;
int state = GetAsyncKeyState(VK_LEFT);

if (state && yflag==0)
{
yflag=1;
startRow+=1;
endRow+=1;
yt++;
printf("yt: %d",yt);
}
else if (!state && yflag==1)
{
yflag=0;
}
}


ok this works. Now just to be fussy, I needed the press to tick over when holding down the key instead of a whole key press for a move. Like moving in a map with just holding down the key.
Maybe I need a timer on the keypress instead.


Lets assume that you may want to add more keycommands later and you want to do this in a neat way. First of all i would make a function that stores the current state of the keyboard, next i would use this state to define what should be done in the render loop. By calculating the time that has passed between consecutive render loops i can make the movement of the map independent of the speed of your computer.

All these functions are written on the fly, so if they don't compile let me know...

First my function to get the state of the keyboard:

void GetKeyboardState(int* keyboard)
{
register int i; for (i=0; i<256; i++) {
keyboard[i] = (GetAsyncKeyState(i) ? 1 : 0);
}
}


Now this function gives the time that has past between calls in milliseconds. For high end engines you'd use a performance timer, but lets keep it simple for now and use clock(). Be sure to include <time.h> or <ctime.h>
I am assuming that CLOCKS_PER_SEC == 1000, because i don't feel like writing to much code :p


void GetDeltaTime(int* dt)
{
static clock_t prev = clock(); //one time initialize, first call gives 0

clock_t current = clock();
*dt = current-prev; //set dt to ms that have passed
prev = current;
}


Now lets say you want to use the cursorkeys to move your map. So we will be updating (x,y) and we want to move them by 50 pixels per second as long as the key is pressed.


void render()
{
static int keyboard[256];
static int deltaTime;

static float pixels_per_ms = 50.0/1000.0;
static float x = 0, y = 0;

//get the keyboard state and delta time (using a pointer)
GetKeyboardState(keyboard);
GetDeltaTime(&deltaTime);

//calculate new coordinate
x += keyboard[VK_RIGHT] *pixels_per_ms*deltaTime;
x -= keyboard[VK_LEFT] *pixels_per_ms*deltaTime;

y += keyboard[VK_UP] *pixels_per_ms*deltaTime;
y -= keyboard[VK_DOWN] *pixels_per_ms*deltaTime;

//now use these x,y to position the map
}


This is how it would look like. Once again, i didn't compile it so i might have made a few mistakes, and you should update the getdeltatime function when you feel up to it, however... i hope this takes you in the right direction.

Greetings

Share this post


Link to post
Share on other sites
Limitz approach looks pretty good but all I would say is that rather than having to call 256 GetAsyncKeyStates each frame, performance might be improved by having a global (boo, hiss) bool Keys[256]=false array that you update in response to WM_KEYUP and WM_KEYDOWN messages.

Or perhaps a better solution than a global, such as a RegisterKeyState and GetKeyState function pair that hide the array away in a unit somewhere.

Share this post


Link to post
Share on other sites
Quote:
Original post by EasilyConfused
Limitz approach looks pretty good but all I would say is that rather than having to call 256 GetAsyncKeyStates each frame, performance might be improved by having a global (boo, hiss) bool Keys[256]=false array that you update in response to WM_KEYUP and WM_KEYDOWN messages.

Or perhaps a better solution than a global, such as a RegisterKeyState and GetKeyState function pair that hide the array away in a unit somewhere.


You are right, but it is the simplest approach for now. It works great while developing when you don't know yet what keys to use. It was the first keyboardstate retriever i actually used. After this i went on doing it like you proposed, however i used a singleton class that stored the state while retrieving WM_KEYDOWN/WM_KEYUP messages. I stored the state as well as the action to be able to use trigger as well a toggle keys.

Now i use DirectInput :)

Greetings...

Share this post


Link to post
Share on other sites

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