question about input in sdl

i am trying to write an input class for my sdl game. the class is seperated from my main game loop, but it is called to check for input every frame. the function works more or less the way i had intended, except for one thing: when i do the input for moving the player, it will only move once for every time i press the button.

is this because i dont have my input code in the main loop? is there any way to have the input in a seperate function? i want this because that way i could call the function from anywhere in the code, not only from the main loop.
You have to keep track of which keys are down and up. Normally you get notified for when a key does down, and then notified again when the key goes up. You can set a boolean true when one goes down, then false when it goes up (you need a boolean for each key you intend to check for). Then you can check the boolean to determine whether they're holding a key or not ;)
i was considering making my input function a boolean type, but seeing as there is a lot of different inputs that the game are checking, i dont see a way to do so. there is only to different values that a boolean can hold, so how could i possible make the program know which input is true, and wich input is false?
You can use SDL_GetKeyState to check if a key is down or not.
http://www.libsdl.org/cgi/docwiki.cgi/SDL_GetKeyState
i dont think you quite understand my problem, peter. i dont have a problem with checking if the key is pressed, i have a problem with passing witch key is beingpressed (if any) from my input() function.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
int getInput(){

			while (SDL_PollEvent ( &event )){
				switch (event.type){
					case SDL_QUIT:
						return 0;
						break;
					case SDL_KEYDOWN:
						switch (event.key.keysym.sym){
							case SDLK_UP:
								return 2;
								break;
							case SDLK_DOWN:
								return 3;
								break;
							case SDLK_LEFT:
								return 4;
								break;
							case SDLK_RIGHT:
								return 5;
								break;
					case SDL_KEYUP:
						switch (event.key.keysym.sym){
							case SDLK_UP:
								return 1;
								break;
							case SDLK_DOWN:
								return 1;
								break;
							case SDLK_LEFT:
								return 1;
								break;
							case SDLK_RIGHT:
								return 1;
								break;
						}
					}
				}
			}
			return 1;
		}


that is the way i am checking for input, and all the return statements returns different integer, so the main game function containing the main loop know wich key is being pressed. i want a way to get the same effect as when i would have this in my main loop, (if i held down the up key, the character would go up etc.) but i want it to be in a seperate function if possible, cause i want every function to have acces to it, and not have to rewrite it for every function that required input.
Peter is right, you're probably better off with SDL_GetKeyState. But you can work with events too if you want.

You basically have 2 options:

1) Use events and keep track of the real-time keydown state:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
bool keys[4];  // somewhere with greater scope

int getInput()
{
//...
case SDL_KEYDOWN:
  //..
  case SDLK_UP:  keys[0] = true;  break;
  case SDLK_DOWN:  keys[1] = true;  break;
  //..
case SDL_KEYUP:
  case SDLK_UP:  keys[0] = false; break;
  //..


  if(keys[0])  return 2;
  if(keys[1])  return 3;
  if(keys[2])  return 4;
  if(keys[3])  return 5;
  return 1;



or 2) Use SDL_GetKeyState to get the realtime state of a key so you don't have to track it yourself:

1
2
3
4
5
Uint8* keystate = SDL_GetKeyState(NULL);

if(keystate[SDLK_UP]) return 2;
if(keystate[SDLK_DOWN]) return 3;
//... 
i tried to do it both ways, but none of them seems to work.

the event method made the player walk in the direction that the first return value was equal to.
the keystate method made my program nor respond at all.

at this moment i think im gonna try to use the keystate method, cause it seems like a good way of doing things, but obviously i have something wrong with my code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Input{
	public:
		int getInput(){
			keystate = SDL_GetKeyState (NULL);

			switch (event.type){
				case SDL_QUIT:
					return 1;
					break;
			}

			if (keystate [SDLK_UP])
				return 2;
			else if (keystate [SDLK_DOWN])
				return 3;
			else if (keystate [SDLK_LEFT])	
				return 4;
			else if (keystate [SDLK_RIGHT])
				return 5;
			else 
				return 0;
		}

	private:
		Uint32 color;
		Uint8* keystate;
		SDL_Event event;
};


can anyone tell me where i screwed up?
You still need to handle events in a loop like you did before. As you have it now, event is uninitialized and is never updated.

I even think it's necessary to call SDL_PollEvent for the keystate to actually get updated.
the program run now, however i am back where i started (only using keystates instead of events now)

the code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
class Input{
	public:
		int getInput(){
			keystate = SDL_GetKeyState (NULL);
			while (SDL_PollEvent ( &event )){
				switch (event.type){
					case SDL_QUIT:
						return 1;
						break;
						case SDL_KEYDOWN:
							if (keystate [SDLK_UP])
									return 2;
							else if (keystate [SDLK_DOWN])
								return 3;
							else if (keystate [SDLK_LEFT])
								return 4;
							else if (keystate [SDLK_RIGHT])
								return 5;
							break;
						case SDL_KEYUP:
							if (keystate [SDLK_UP])
									return 2;
							else if (keystate [SDLK_DOWN])
								return 3;
							else if (keystate [SDLK_LEFT])
								return 4;
							else if (keystate [SDLK_RIGHT])
								return 5;
							break;
				}
			}

			
				return 0;
		}

	private:
		Uint32 color;
		Uint8* keystate;
		SDL_Event event;
};


i have to keep pressing the keys for the player to move, and it wont work to just keep the key pressed. i would eliminate this problem i i put the input checking directly into the main loop, butas i said i want to be able to call the input checking from anywhere in my code, without having to rewrite it for every single function i want to have it in.
events are only sent when the keys are pressed/released.

Take the keystate checks out of the event checking loop. They are not events.
care to explain a bit more detailed. wasnt i supposed to have it inside of the loop?
No, you're not.

It helps if you understand how event queues work. When something of interest happens, SDL will add an event to the queue.

This code:
1
2
3
4
5
while (SDL_PollEvent ( &event )){
    switch (event.type){
        //...
    }
}


SDL_PollEvent tells SDL "okay, give me the next event that's in the queue". And the switch says "what kind of event is it?"

Now if there's no events in the queue, that loop isn't going to run, because SDL_PollEvent will have no event to give you.

With that in mind, when you press a key, SDL sends 1 event. When you release a key, SDL sends another event. It does not continually send events as you hold the key down. So any code that you put in the case SDL_KEYDOWN: section will run only when the key is first pressed.



Conversely, SDL_GetKeyState does not use the event system, and instead gives you the realtime pressed/released state of any key. You can check it any time and it will tell you whether the key is pressed or not.


With that in mind, think about what your code does...

When you first press the Up key:
- SDL_PollEvent will give you the SDL_KEYDOWN event
- your switch will process it
- SDL_GetKeyState will tell you that the Up key is pressed
- you will return 2 (correct behavior)

The next frame - when up is still being held:
- SDL_PollEvent has no pending events, so it will give you nothing
- your switch will not be run, since there's no event to check
- (SDL_GetKeyState is never checked)
- you will return 0 (incorrect behavior)
Last edited on
thanks, it works now :D
and i really apreciate the lesson on how events work.
Topic archived. No new replies allowed.