Sign in to follow this  
Strumluff

Handling Input in SDL

Recommended Posts

Hi, I'm new to SDL and have been playing around with it and now I've got a little problem and hope to get a little more help from you pros out there. I have an event loop to check for input from the user. Within this event loop it deals with movement using arrow keys and when the enter key is pressed i wish to obtain an input from the user. I thought to do this I can enable another event loop (or something else if there is an alternative) so it can take in a value entered by the user using the keyboard and store it in a variable. I have the other event loop written, so that when the enter key in the first event loop is pressed, the second event loop will only check for KEYDOWN events and store them to a string which i can then convert to an integer and strore in my variable. The problem: It appears that the first loop still runs while the second loop is running, so when i press enter on the first event loop i can enter a value but the key presses that are meant for the second loop are effected in the first loop too! If this helps I'll show the small section of code that does this: From the first event loop: (the handle_input() function contains the second loop) if (event.key.keysym.sym == SDLK_RETURN) { //If the user hasn't entered a value yet if( valueEntered == false ) { SDL_FreeSurface( instr_text ); instr_text = TTF_RenderText_Solid( betfont, "Enter value for square: ", Orange); DrawSprite( gScreen, instr_text , 560, 180); SDL_Flip(gScreen); //Get user input handle_input(); The function then runs as follows so you can see the way the loop is set up: void handle_input(){ while(SDL_PollEvent(&InEvent)) { if ( valueEntered == false ) { //If a key was pressed if( InEvent.type == SDL_KEYDOWN ) { //Keep a copy of the current version of the string std::string temp = str; ...etc. etc. I hope this doesnt sound too confusing, and really appreciate any help! Thanks

Share this post


Link to post
Share on other sites
As can been seen, as soon as the PollEvent becomes false, u are going to exit the second input loop, as this is real time u are going to get out of the second loop very fast if u never enter the values fast enough. So it is highly possible that by the time u have enter the 2nd value u want to input. You are already in the first event loop already. Thus u have to make a loop condition such like Done == false, and enable the Done to true inside the second loop AFTER u have get the variable input u want like say after person type values and press enter again. I hope my explanation is clear enough.

Share this post


Link to post
Share on other sites
It's often a bad idea to have separate input loops because of the increased complexity. Instead, you could choose to have a state machine in the input handling which does different processing depending on what state you're currently in.

eg. (minimal pseudocode)

switch (state)
{
case STATE_GETTINGTEXT:
// add keypress to string
break;
case STATE_NORMAL:
if (keypress == SDLK_RETURN)
state = STATE_GETTINGTEXT;
}

Share this post


Link to post
Share on other sites
Thank you for the assistance, it has proved helpful :)

Apologies for posting in the beginner forum also I only noticed that this forum included help for SDL after my first post.

Share this post


Link to post
Share on other sites
Hi again,
I've been trying this method of using a state machine to divide the way i get keyboard input. However there is a problem putting this to practice. What seems to happen is when the program is in the STATE_GETTINGTEXT state, i have a condition within the event loop here that changes the state to STATE_NORMAL when the enter key is pressed after I have assigned the variable acquired from the function.
Despite the fact that the state has now been changed to normal it still loops in the event here a few times before going back to the state switch and changing to normal. When the normal event loop goes through now for some reason it skips right over the event loop and just draws what i have in my draw functions, the program then loops again back to the beginning of normal and skips over the event loop (as if there were no more events left in the queue?)
I don't know how to get around this and could use some assistance.

My code is as follows:


while( quit == false ){
//Remove an event from the queue
while (SDL_PollEvent(&event)) {
switch (state){ //State machine to switch between normal and input
case STATE_GETTINGTEXT:
instr_text = TTF_RenderText_Solid( betfont, "Enter value for square: ", Orange);
handle_input();
//cout << "Enter amount you wish to bet" << endl;
//cin >> money;
//SDL_FreeSurface( money_text );
//itoa (money, betstr, 10); //Convert int to char
//money_text = TTF_RenderText_Solid( betfont, betstr, Green);
//
//Add keypress to string
break;
case STATE_NORMAL:
switch (event.type) { //Check type of event and handle accordingly
case SDL_KEYDOWN:
break;
case SDL_KEYUP:
if (event.key.keysym.sym == SDLK_UP){
if (fCounterY <= 140) {
cout << "Can't move out of grid bounds" << endl;
}
else{
fCounterY -= 55;
y--;
}
}
if (event.key.keysym.sym == SDLK_DOWN){
if (fCounterY >= 580){
cout << "Can't move out of grid bounds" << endl;
}
else{
fCounterY += 55;
y++;
}
}
if (event.key.keysym.sym == SDLK_LEFT){
if (fCounterX <= 50){
cout << "Can't move out of grid bounds" << endl;
}
else{
fCounterX -= 55;
x--;
}
}
if (event.key.keysym.sym == SDLK_RIGHT){
if (fCounterX >= 490){
cout << "Can't move out of grid bounds" << endl;
}
else{
fCounterX += 55;
x++;
}
}
if (event.key.keysym.sym == SDLK_RETURN)
{
state = STATE_GETTINGTEXT;
}
if (event.key.keysym.sym == SDLK_ESCAPE)
quit = true;
break;
case SDL_QUIT:
quit = true;
break;
default:
break;
}
break;
default:
break;
}
}


All the drawing occurs beneath this.
The event loop for the GETTINGTEXT state is within the handle_input() function shown here:


void Sudoku::handle_input()
{
//Enable Unicode
SDL_EnableUNICODE( SDL_ENABLE );
SDL_Color White = { 0xFF, 0xFF, 0xFF };
SDL_Color Orange = { 255, 114, 0};
//bool done = false;
//while (done == false){
// while( SDL_PollEvent(&event) ){
switch (event.type){
case SDL_KEYDOWN:
if ( valueEntered == false )
{
//Keep a copy of the current version of the string
std::string temp = str;

//If the string less than 1 digit
if( str.length() < 1 )
{
//If the key is a number between 1 and 9
if( ( event.key.keysym.unicode >= (Uint16)'1' ) && ( event.key.keysym.unicode <= (Uint16)'9' ) )
{
//Append the character
str += (char)event.key.keysym.unicode;
}
}
//If backspace was pressed and the string isn't blank
if( ( event.key.keysym.sym == SDLK_BACKSPACE ) && ( str.length() != 0 ) )
{
//Remove a character from the end
str.erase( str.length() - 1 );
}

//If the string was changed
if( str != temp )
{
//Free the old surface
SDL_FreeSurface( inputText );

//Render a new text surface
inputText = TTF_RenderText_Solid( betfont, str.c_str(), White );
}
//If the enter key was pressed
if( ( event.type == SDL_KEYDOWN ) && ( event.key.keysym.sym == SDLK_RETURN ) )
{
InValue = atoi(str.c_str());
GameGrid.setPValue(x, y, InValue);

//Change the flags
valueEntered = true;
// done = true;
state = STATE_NORMAL;
}
}
// }
//Disable Unicode
SDL_EnableUNICODE( SDL_DISABLE );
}



This should be enough to show you what its doing, I could really use some help, thanks again.

Strumluff

Share this post


Link to post
Share on other sites
Hi Strumluff,
You still have two input loops though you tried to hide it. Also you're doing all state processing inside the SDL_PollEvent(event/input) loop which is generally not a good ideal.

Clean out the SDL_PollEvent() loop. The main application state should not change inside it. Make sure that event/input loop is the only one. Save whatever events you need to process and do little else inside the loop.

If you do this, it will simplify your program. You will be able to spot any logic errors that exist. You will succeed.

Good Luck.

Share this post


Link to post
Share on other sites
Thanks Jack, got it sorted, I've decided to change between states by just using a boolean variable to check for the condition and an if statement to divide which function to do, all under 1 event loop now.

Thanks for your help!!

Share this post


Link to post
Share on other sites
Hey,
I didn't read all of your post so I am not sure if this would exactly help, but ths is how I do input in all of my games. I check the state of the keys. Here is some example code although it is not using your code.


Uint8* keysheld=NULL;
int main(int argc, char* argv[])
{
//init SDL here
//you know, do screen=SDL_GetVideoMode stuff here
//now we get the state of the keys basically
keysheld=SDL_GetKeyState(0);
//now, we can just use keysheld like this:
if(keysheld[SDLK_RETURN])
{
std::cout<<"You have pressed return";
}
}



That was just some QUICK example code to help you to maybe get started. I hope any of this helped, and good luck!


Chad.

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