SDL: Controlling input

Whether you're a newbie or an experienced programmer, any questions, help, or just talk of any language will be welcomed here.

Moderator: Coders of Rage

mary
Chaos Rift Newbie
Chaos Rift Newbie
Posts: 33
Joined: Tue Apr 27, 2010 2:13 pm

SDL: Controlling input

Post by mary »

I currently am making a project where I apply a grid to the screen if the user presses the g button. The problem I ran into is that if I when I press the button the grid flashes on and off, this is because the g key controls turning on and off the key, is there a way that I can make it so that if the key is pressed it will only switch it once? my code is as bellow

Code: Select all

#include <SDL/SDL.h>
SDL_Surface *buffer = NULL;
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480

int main (int argc, char *argv[])
{
	SDL_Init(SDL_INIT_VIDEO);
	buffer = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32, SDL_SWSURFACE);
	bool done = false;
	SDL_Event event;
	SDL_WM_SetCaption("Window", NULL);
	bool grid = false;
	while(!done)
	{
	SDL_FillRect(buffer,NULL,0x000000);
	SDL_Rect area = {520, 360, (SCREEN_WIDTH -120), (SCREEN_HEIGHT -120)}; //{x,y,w,h}
	SDL_FillRect(buffer,&area,0xBBBBBB);
	Uint8 *key = SDL_GetKeyState (NULL);
	if (key[SDLK_g])
	{
		if (grid == true)
		{
		grid = false;
		}		
		else if (grid == false)
		{
		grid = true;
		}
	}
	if (grid == true)
	{
		for (int i = 0; i < SCREEN_WIDTH; i+=40)
		{
		SDL_Rect grid_vertical = {i, 0, 2, SCREEN_HEIGHT};
		SDL_FillRect(buffer,&grid_vertical,0xAAAAAA);
		}

		for (int i = 0; i < SCREEN_HEIGHT; i+=40)
		{
		SDL_Rect grid_horizontal = {0, i, SCREEN_WIDTH, 2};
		SDL_FillRect(buffer,&grid_horizontal,0xAAAAAA);
		}
	}

	SDL_Flip(buffer);
		while(SDL_PollEvent(&event))
		{
			if (event.type == SDL_QUIT)
			{
				done = true;
			}
		}	
	}
	SDL_Quit();
	return 0;
}
User avatar
eatcomics
ES Beta Backer
ES Beta Backer
Posts: 2528
Joined: Sat Mar 08, 2008 7:52 pm
Location: Illinois

Re: SDL: Controlling input

Post by eatcomics »

That looks like it should work, but it looks like you're going to have to do a switch statement

Code: Select all

SDL_Event event;
while (SDL_PollEvent(&event){
    if (event.type == SDL_KEYDOWN){
        switch (event.key.keysym.sym){
            case SDLK_g: 
                   if (grid == true){ 
                        grid = false 
                   }
                   else{ 
                        grid = true 
                   }; 
                   break;
        }
    }
}
Last edited by eatcomics on Wed Apr 28, 2010 4:01 pm, edited 1 time in total.
Image
pritam
Chaos Rift Demigod
Chaos Rift Demigod
Posts: 991
Joined: Thu Nov 13, 2008 3:16 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Amiga, PSOne, NDS
Programming Language of Choice: C++
Location: Sweden

Re: SDL: Controlling input

Post by pritam »

Try this, I hope it works. Haven't tried it.

Code: Select all

#include <SDL/SDL.h>
SDL_Surface *buffer = NULL;
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480

int main (int argc, char *argv[])
{
	SDL_Init(SDL_INIT_VIDEO);
	buffer = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32, SDL_SWSURFACE);
	bool done = false;
	SDL_Event event;
	SDL_WM_SetCaption("Window", NULL);
	bool grid = false;
	bool gKey = false;
	while(!done)
	{
	SDL_FillRect(buffer,NULL,0x000000);
	SDL_Rect area = {520, 360, (SCREEN_WIDTH -120), (SCREEN_HEIGHT -120)}; //{x,y,w,h}
	SDL_FillRect(buffer,&area,0xBBBBBB);
	Uint8 *key = SDL_GetKeyState (NULL);
	if (key[SDLK_g])
	{
		if( gKey == false ) {
			gKey = true;
			if (grid == true)
			{
			grid = false;
			}		
			else if (grid == false)
			{
			grid = true;
			}
		}
	} else {
		gKey = false;
	}
	if (grid == true)
	{
		for (int i = 0; i < SCREEN_WIDTH; i+=40)
		{
		SDL_Rect grid_vertical = {i, 0, 2, SCREEN_HEIGHT};
		SDL_FillRect(buffer,&grid_vertical,0xAAAAAA);
		}

		for (int i = 0; i < SCREEN_HEIGHT; i+=40)
		{
		SDL_Rect grid_horizontal = {0, i, SCREEN_WIDTH, 2};
		SDL_FillRect(buffer,&grid_horizontal,0xAAAAAA);
		}
	}

	SDL_Flip(buffer);
		while(SDL_PollEvent(&event))
		{
			if (event.type == SDL_QUIT)
			{
				done = true;
			}
		}	
	}
	SDL_Quit();
	return 0;
}
User avatar
Ginto8
ES Beta Backer
ES Beta Backer
Posts: 1064
Joined: Tue Jan 06, 2009 4:12 pm
Programming Language of Choice: C/C++, Java

Re: SDL: Controlling input

Post by Ginto8 »

Have a variable hold the previous keystate.
I added that and cleaned your code up a little :) (changes are listed in the comments):

Code: Select all

#include <SDL/SDL.h>

// the C++ const is a better choice than the C #define
const int SCREEN_WIDTH 640;
const int SCREEN_HEIGHT 480;

// the { doesn't have to be on the same line as main(), but since I'm editing it, and that's my style,
// that's how I made it
int main (int argc, char *argv[]) {
   // moved this here because global vars are bad practice
   SDL_Surface *buffer = NULL;
   // variables of the same type can be declared in a comma-separated list
   // and bools are by default false
   // gDown is a bool of whether or not G was down last frame
   bool grid,gDown;
   SDL_Event event;
   // calling functions and declaring variables in a mishmosh is bad taste, so I separated the two
   SDL_Init(SDL_INIT_VIDEO);
   buffer = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32, SDL_SWSURFACE);
   SDL_WM_SetCaption("Window", NULL);
   
   // an infinite loop
   while(true) {
      // inside of {'s, there should be indentation
      SDL_FillRect(buffer,NULL,0x000000);
      SDL_Rect area = {520, 360, (SCREEN_WIDTH -120), (SCREEN_HEIGHT -120)}; //{x,y,w,h}
      SDL_FillRect(buffer,&area,0xBBBBBB);
      Uint8 *key = SDL_GetKeyState (NULL);
      // in if()'s, {s are only needed for multi-line actions
      // ! is the opposite when it comes to bools
      // if b is true, then !b is false
      // and vice versa
      if(key[SDLK_g] && !gDown)
         grid = !grid;
      gDown = key[SDLK_g];
      // if(x) is basically the same as if((bool)x == true), so you don't need the "== true"
      // and again, the { on the same line is just a stylistic preference
      if(grid) {
         for (int i = 0; i < SCREEN_WIDTH; i+=40) {
            SDL_Rect grid_vertical = {i, 0, 2, SCREEN_HEIGHT};
            SDL_FillRect(buffer,&grid_vertical,0xAAAAAA);
         }

         for (int i = 0; i < SCREEN_HEIGHT; i+=40) {
         SDL_Rect grid_horizontal = {0, i, SCREEN_WIDTH, 2};
         SDL_FillRect(buffer,&grid_horizontal,0xAAAAAA);
         }
      }

      SDL_Flip(buffer);
      while(SDL_PollEvent(&event)) {
         // goto should only be used in situations like this, where there are nested loops
         // otherwise, STAY AWAY FROM THEM
         if (event.type == SDL_QUIT)
            goto nested_loop_break;
      }   
   }
nested_loop_break:
   SDL_Quit();
   return 0;
}
In case anyone bitches about the goto, it was ONLY for breaking out of nested loops. I have a thing against "done" variables for main game loops, so I prefer things like break. But since break wouldn't provide the wanted affect, I went with a goto for the SOLE PURPOSE of breaking out of the nested loop. AND I made an explicit comment stating NOT to use gotos in any other situation.

Edit: now WHY was I the only one to help with the overall bad practices? You people obviously forgotten what it's like to be a newbie :( .
Edit 2: made buffer local rather than global
Last edited by Ginto8 on Wed Apr 28, 2010 4:15 pm, edited 2 times in total.
Quit procrastinating and make something awesome.
Ducky wrote:Give a man some wood, he'll be warm for the night. Put him on fire and he'll be warm for the rest of his life.
User avatar
eatcomics
ES Beta Backer
ES Beta Backer
Posts: 2528
Joined: Sat Mar 08, 2008 7:52 pm
Location: Illinois

Re: SDL: Controlling input

Post by eatcomics »

Good to see a couple of people knew why that wasn't working, use theirs because switch statements are slow
Image
User avatar
Ginto8
ES Beta Backer
ES Beta Backer
Posts: 1064
Joined: Tue Jan 06, 2009 4:12 pm
Programming Language of Choice: C/C++, Java

Re: SDL: Controlling input

Post by Ginto8 »

eatcomics wrote:Good to see a couple of people knew why that wasn't working, use theirs because switch statements are slow
and because you approached it completely wrong.
Given the typical key repeat rate of about 20 times per second, his var would toggle slower, but it would still toggle repeatedly. What you need to do is store a var stating whether or not the key was down the previous frame, and use that to determine if it's a new press or not.
Quit procrastinating and make something awesome.
Ducky wrote:Give a man some wood, he'll be warm for the night. Put him on fire and he'll be warm for the rest of his life.
User avatar
eatcomics
ES Beta Backer
ES Beta Backer
Posts: 2528
Joined: Sat Mar 08, 2008 7:52 pm
Location: Illinois

Re: SDL: Controlling input

Post by eatcomics »

You are correct, I don't know why I didn't think of that, I've even had that problem before, a switch statement was the first thing that came to mind
Image
User avatar
LeonBlade
Chaos Rift Demigod
Chaos Rift Demigod
Posts: 1314
Joined: Thu Jan 22, 2009 12:22 am
Current Project: Trying to make my first engine in C++ using OGL
Favorite Gaming Platforms: PS3
Programming Language of Choice: C++
Location: Blossvale, NY

Re: SDL: Controlling input

Post by LeonBlade »

Ginto8 wrote:Have a variable hold the previous keystate.
I added that and cleaned your code up a little :) (changes are listed in the comments):

Code: Select all

#include <SDL/SDL.h>

// the C++ const is a better choice than the C #define
const int SCREEN_WIDTH 640;
const int SCREEN_HEIGHT 480;

// the { doesn't have to be on the same line as main(), but since I'm editing it, and that's my style,
// that's how I made it
int main (int argc, char *argv[]) {
   // moved this here because global vars are bad practice
   SDL_Surface *buffer = NULL;
   // variables of the same type can be declared in a comma-separated list
   // and bools are by default false
   // gDown is a bool of whether or not G was down last frame
   bool grid,gDown;
   SDL_Event event;
   // calling functions and declaring variables in a mishmosh is bad taste, so I separated the two
   SDL_Init(SDL_INIT_VIDEO);
   buffer = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32, SDL_SWSURFACE);
   SDL_WM_SetCaption("Window", NULL);
   
   // an infinite loop
   while(true) {
      // inside of {'s, there should be indentation
      SDL_FillRect(buffer,NULL,0x000000);
      SDL_Rect area = {520, 360, (SCREEN_WIDTH -120), (SCREEN_HEIGHT -120)}; //{x,y,w,h}
      SDL_FillRect(buffer,&area,0xBBBBBB);
      Uint8 *key = SDL_GetKeyState (NULL);
      // in if()'s, {s are only needed for multi-line actions
      // ! is the opposite when it comes to bools
      // if b is true, then !b is false
      // and vice versa
      if(key[SDLK_g] && !gDown)
         grid = !grid;
      gDown = key[SDLK_g];
      // if(x) is basically the same as if((bool)x == true), so you don't need the "== true"
      // and again, the { on the same line is just a stylistic preference
      if(grid) {
         for (int i = 0; i < SCREEN_WIDTH; i+=40) {
            SDL_Rect grid_vertical = {i, 0, 2, SCREEN_HEIGHT};
            SDL_FillRect(buffer,&grid_vertical,0xAAAAAA);
         }

         for (int i = 0; i < SCREEN_HEIGHT; i+=40) {
         SDL_Rect grid_horizontal = {0, i, SCREEN_WIDTH, 2};
         SDL_FillRect(buffer,&grid_horizontal,0xAAAAAA);
         }
      }

      SDL_Flip(buffer);
      while(SDL_PollEvent(&event)) {
         // goto should only be used in situations like this, where there are nested loops
         // otherwise, STAY AWAY FROM THEM
         if (event.type == SDL_QUIT)
            goto nested_loop_break;
      }   
   }
nested_loop_break:
   SDL_Quit();
   return 0;
}
In case anyone bitches about the goto, it was ONLY for breaking out of nested loops. I have a thing against "done" variables for main game loops, so I prefer things like break. But since break wouldn't provide the wanted affect, I went with a goto for the SOLE PURPOSE of breaking out of the nested loop. AND I made an explicit comment stating NOT to use gotos in any other situation.

Edit: now WHY was I the only one to help with the overall bad practices? You people obviously forgotten what it's like to be a newbie :( .
Edit 2: made buffer local rather than global
Or you could just use a variable and break out of the loop that way, what's your problem with using them?
There's no place like ~/
User avatar
eatcomics
ES Beta Backer
ES Beta Backer
Posts: 2528
Joined: Sat Mar 08, 2008 7:52 pm
Location: Illinois

Re: SDL: Controlling input

Post by eatcomics »

I'd say a local done variable is much better than using a goto... like seriously why is that goto statement any better than simply putting a bool done; before your loop?
Image
User avatar
Ginto8
ES Beta Backer
ES Beta Backer
Posts: 1064
Joined: Tue Jan 06, 2009 4:12 pm
Programming Language of Choice: C/C++, Java

Re: SDL: Controlling input

Post by Ginto8 »

LeonBlade wrote:
Ginto8 wrote:Have a variable hold the previous keystate.
I added that and cleaned your code up a little :) (changes are listed in the comments):

Code: Select all

#include <SDL/SDL.h>

// the C++ const is a better choice than the C #define
const int SCREEN_WIDTH 640;
const int SCREEN_HEIGHT 480;

// the { doesn't have to be on the same line as main(), but since I'm editing it, and that's my style,
// that's how I made it
int main (int argc, char *argv[]) {
   // moved this here because global vars are bad practice
   SDL_Surface *buffer = NULL;
   // variables of the same type can be declared in a comma-separated list
   // and bools are by default false
   // gDown is a bool of whether or not G was down last frame
   bool grid,gDown;
   SDL_Event event;
   // calling functions and declaring variables in a mishmosh is bad taste, so I separated the two
   SDL_Init(SDL_INIT_VIDEO);
   buffer = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, 32, SDL_SWSURFACE);
   SDL_WM_SetCaption("Window", NULL);
   
   // an infinite loop
   while(true) {
      // inside of {'s, there should be indentation
      SDL_FillRect(buffer,NULL,0x000000);
      SDL_Rect area = {520, 360, (SCREEN_WIDTH -120), (SCREEN_HEIGHT -120)}; //{x,y,w,h}
      SDL_FillRect(buffer,&area,0xBBBBBB);
      Uint8 *key = SDL_GetKeyState (NULL);
      // in if()'s, {s are only needed for multi-line actions
      // ! is the opposite when it comes to bools
      // if b is true, then !b is false
      // and vice versa
      if(key[SDLK_g] && !gDown)
         grid = !grid;
      gDown = key[SDLK_g];
      // if(x) is basically the same as if((bool)x == true), so you don't need the "== true"
      // and again, the { on the same line is just a stylistic preference
      if(grid) {
         for (int i = 0; i < SCREEN_WIDTH; i+=40) {
            SDL_Rect grid_vertical = {i, 0, 2, SCREEN_HEIGHT};
            SDL_FillRect(buffer,&grid_vertical,0xAAAAAA);
         }

         for (int i = 0; i < SCREEN_HEIGHT; i+=40) {
         SDL_Rect grid_horizontal = {0, i, SCREEN_WIDTH, 2};
         SDL_FillRect(buffer,&grid_horizontal,0xAAAAAA);
         }
      }

      SDL_Flip(buffer);
      while(SDL_PollEvent(&event)) {
         // goto should only be used in situations like this, where there are nested loops
         // otherwise, STAY AWAY FROM THEM
         if (event.type == SDL_QUIT)
            goto nested_loop_break;
      }   
   }
nested_loop_break:
   SDL_Quit();
   return 0;
}
In case anyone bitches about the goto, it was ONLY for breaking out of nested loops. I have a thing against "done" variables for main game loops, so I prefer things like break. But since break wouldn't provide the wanted affect, I went with a goto for the SOLE PURPOSE of breaking out of the nested loop. AND I made an explicit comment stating NOT to use gotos in any other situation.

Edit: now WHY was I the only one to help with the overall bad practices? You people obviously forgotten what it's like to be a newbie :( .
Edit 2: made buffer local rather than global
Or you could just use a variable and break out of the loop that way, what's your problem with using them?
I'm not really sure, it's more of a stylistic preference than anything else (I think that an infinite loop makes it look cleaner, because execution actually will stop rather than going through a whole extra iteration). It's not a big thing, but it's my style, sorta like the { on the same line as the if(). I'm the one that edited it, so it's my style that is added. If you don't like it that way, then you don't have to use my code.
Quit procrastinating and make something awesome.
Ducky wrote:Give a man some wood, he'll be warm for the night. Put him on fire and he'll be warm for the rest of his life.
User avatar
LeonBlade
Chaos Rift Demigod
Chaos Rift Demigod
Posts: 1314
Joined: Thu Jan 22, 2009 12:22 am
Current Project: Trying to make my first engine in C++ using OGL
Favorite Gaming Platforms: PS3
Programming Language of Choice: C++
Location: Blossvale, NY

Re: SDL: Controlling input

Post by LeonBlade »

Ginto8 wrote:I'm not really sure, it's more of a stylistic preference than anything else (I think that an infinite loop makes it look cleaner, because execution actually will stop rather than going through a whole extra iteration). It's not a big thing, but it's my style, sorta like the { on the same line as the if(). I'm the one that edited it, so it's my style that is added. If you don't like it that way, then you don't have to use my code.
Understandable, me personally I feel like forcing yourself to BREAK out of a loop seems like the wrong way to do it.
But, if it works it works, I'm not entirely sure what way is better and why... so I'm just going to leave it at that.
There's no place like ~/
User avatar
eatcomics
ES Beta Backer
ES Beta Backer
Posts: 2528
Joined: Sat Mar 08, 2008 7:52 pm
Location: Illinois

Re: SDL: Controlling input

Post by eatcomics »

I agree with leon, and I kinda think it looks weird, but maybe that's because I haven't used a GOTO statement since I first started programming
Image
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

Re: SDL: Controlling input

Post by Falco Girgis »

eatcomics wrote:Good to see a couple of people knew why that wasn't working, use theirs because switch statements are slow
What the fuck are you talking about? A switch statement is no slower than an if/else block. It's the same thing at the assembly level.

Actually, I'm pretty sure they're faster because you're only checking the value of one variable.
User avatar
avansc
Respected Programmer
Respected Programmer
Posts: 1708
Joined: Sun Nov 02, 2008 6:29 pm

Re: SDL: Controlling input

Post by avansc »

might as well bench em and find out, right.

Code: Select all

#include <stdio.h>
#include <mach/mach_time.h>

int main(int argc, char * const argv[])
{
	uint64_t t1 = mach_absolute_time();
	uint64_t t2;

	for(unsigned long a = 0;a < 1000;a++)
	{
		if(a%10 == 0)
		{

		}
	}
	t2 = mach_absolute_time();

	printf("%d\n", t2-t1);

	t1 = mach_absolute_time();

	for(unsigned long a = 0;a < 1000;a++)
	{
		switch (a%10) {
			case 0:
			{
				break;
			}
			default:
				break;
		}
	}
	t2 = mach_absolute_time();

	printf("%d\n", t2-t1);

    return 0;
}

2872 - if
2864 - switch

not sure what those units are, i believe nano seconds, anyways, looks like the switch for same function is a nano turd faster.
Some person, "I have a black belt in karate"
Dad, "Yea well I have a fan belt in street fighting"
User avatar
short
ES Beta Backer
ES Beta Backer
Posts: 548
Joined: Thu Apr 30, 2009 2:22 am
Current Project: c++, c
Favorite Gaming Platforms: SNES, PS2, SNES, SNES, PC NES
Programming Language of Choice: c, c++
Location: Oregon, US

Re: SDL: Controlling input

Post by short »

compiler optimizations make switch statements faster then if else blocks.
My github repository contains the project I am currently working on,
link: https://github.com/bjadamson
Post Reply