C SDL Keyboard Events SDL_KEYUP Triggering When Key Is Down - c

I am using SDL in C, and I'm trying to make a character move on the screen when a key is pressed, and stop when it is released, but it seems as if the KEYUP event is triggering when the key is still being held down. If I remove the KEYUP section in pressed(), the characters will slide across the screen, but obviously won't stop on their own. If I leave the KEYUP section in, I have to press the key repeatedly to move them across the screen.
Any idea what I'm doing wrong?
Here's what I have:
...
int done = 0;
while (done==0)
{
pressed();
if (kenter == 1)
{
state = 1;
subscreen();
}
if (kescape == 1)
{
done = 1;
}
if (kup == 1)
{
playery += -2;
}
if (kdown == 1)
{
playery += 2;
}
if (kright == 1)
{
playerx += 2;
}
if (kleft == 1)
{
playerx += - 2;
}
...
int pressed ()
{
SDL_Event keyevent;
while (SDL_PollEvent(&keyevent))
{
switch(keyevent.type)
{
case SDL_KEYDOWN:
switch(keyevent.key.keysym.sym)
{
case SDLK_RETURN:
{
kenter = 1;
break;
}
case SDLK_ESCAPE:
{
kescape = 1;
break;
}
case SDLK_a:
{
ka = 1;
break;
}
case SDLK_s:
{
ks = 1;
break;
}
case SDLK_UP:
{
kup = 1;
break;
}
case SDLK_DOWN:
{
kdown = 1;
break;
}
case SDLK_RIGHT:
{
kright = 1;
break;
}
case SDLK_LEFT:
{
kleft = 1;
break;
}
default:
break;
}
}
switch(keyevent.type)
{
case SDL_KEYUP:
switch(keyevent.key.keysym.sym)
{
case SDLK_RETURN:
{
kenter = 0;
break;
}
case SDLK_ESCAPE:
{
kescape = 0;
break;
}
case SDLK_a:
{
ka = 0;
break;
}
case SDLK_s:
{
ks = 0;
break;
}
case SDLK_UP:
{
kup = 0;
break;
}
case SDLK_DOWN:
{
kdown = 0;
break;
}
case SDLK_RIGHT:
{
kright = 0;
break;
}
case SDLK_LEFT:
{
kleft = 0;
break;
}
default:
break;
}
}
}
return 0;
}

I think your switch statements are broken.
Use this less confusing way
int pressed ()
{
SDL_Event event;
while(SDL_PollEvent(&event) )
{
if(event.type == SDLK_KEYDOWN)
{
switch(event.key.keysym.sym)
{
case SDLK_RETURN:
doStuff = 1
break;
default:
break;
}
}
if(event.type == SDLK_KEYUP)
{
switch(event.key.keysym.sym)
{
case SDLK_RETURN:
doStuff = 0;
break;
default:
break;
}
}
}
}
Also important:
SDL Tutorials: Practical Keyboard Input
Oh and avoid using global variables!

Your use of two switch statements is odd and confusing, you should probably fix that.
The issues you're seeing are likely due to keyboard repeat, see the SDL_EnableKeyRepeat() call for how to disable it.

don't use switch. I experienced same thing, but I resolved into using 'if' like this. Maybe switch has 'else if'.
if(event.type == SDL_KEYDOWN){
....
}
if(event.type == SDL_KEYUP){
....
}

Related

Declaring a variable gives an error, makes me think there's something else I'm missing

I have a function in C that compiles fine until I add another case to my switch statement and declare a variable.
Here's the function
void evaluate(int num_inputs) {
struct gate *ptr = gatehead;
while (ptr->next != NULL) {
switch (ptr->kind) {
case 0:
if (get_input_value(ptr->params[0]) && get_input_value(ptr->params[1])) {
write_to_output(true, ptr->output);
} else {
write_to_output(false, ptr->output);
}
break;
case 1:
if (get_input_value(ptr->params[0]) || get_input_value(ptr->params[1])) {
write_to_output(true, ptr->output);
} else {
write_to_output(false, ptr->output);
}
break;
case 2:
if (!(get_input_value(ptr->params[0]) && get_input_value(ptr->params[1]))) {
write_to_output(true, ptr->output);
} else {
write_to_output(false, ptr->output);
}
break;
case 3:
if (!(get_input_value(ptr->params[0])) && !(get_input_value(ptr->params[1]))) {
write_to_output(true, ptr->output);
} else {
write_to_output(false, ptr->output);
}
break;
case 4:
if ((get_input_value(ptr->params[0]) || get_input_value(ptr->params[1])) && !(get_input_value(ptr->params[0]) && get_input_value(ptr->params[1]))) {
write_to_output(true, ptr->output);
} else {
write_to_output(false, ptr->output);
}
break;
case 5:
if (get_input_value(ptr->params[0])) {
write_to_output(false, ptr->output);
} else {
write_to_output(true, ptr->output);
}
break;
case 6:
if (get_input_value(ptr->params[0])) {
write_to_output(true, ptr->output);
} else {
write_to_output(false, ptr->output);
}
break;
case 7:
char* d = "DECODER";
printf("%s", d);
break;
}
ptr = ptr->next;
}
}
If I comment out case 7, everything works fine. Even keeping the print and break compiles, but declaring the char* causes the error "expected expression"
The problem is that the case 7: label is immediately followed by a variable declaration.
case 7:
char* d = "DECODER";
A label can only be applied to a statement, and a declaration is not considered a statement. You can get around this by adding an empty statement before the case label:
case 7:
;
char* d = "DECODER";

Escape delay with a button in a game

I have a problem with a piece of code for a game. I would like to know, how to break the time delay if I press the button.
List of files
At the end, the game writes your end score on the LCD for 10 seconds. And goes back to the wait for start. I want to keep that as it is - the only thing that I want to include is that if I press the button within those 10 seconds I want it to go immediately back to the wait for start.
Function code is here
void DrawGameScore()
{ //&RFONT_8X12 &RFONT_16X26
//char key;
//key = KBD_GetKey();
char txt[10];
UG_FontSelect(&RFONT_16X26);
UG_SetForecolor(C_WHITE);
switch (level){
case 1:
UG_PutString(60,130,"Peasant Score:");
sprintf(txt,"%d",score);
UG_PutString(120,160,txt);
_delay_ms(10000);
break;
case 2:
UG_PutString(60,130,"Knight Score:");
sprintf(txt,"%d",score);
UG_PutString(120,160,txt);
_delay_ms(10000);
break;
case 3:
UG_PutString(60,130,"Queen Score:");
sprintf(txt,"%d",score);
UG_PutString(120,160,txt);
_delay_ms(10000);
break;
case 4:
UG_PutString(60,130,"King Score:");
sprintf(txt,"%d",score);
UG_PutString(120,160,txt);
_delay_ms(10000);
break;
case 5:
UG_PutString(60,130,"God Score:");
sprintf(txt,"%d",score);
UG_PutString(120,160,txt);
_delay_ms(10000);
break;
}
//UG_PutString(60,130,"Final Score:");
//sprintf(txt,"%d",score);
//UG_PutString(120,160,txt);
//_delay_ms(1000);
}
When the game is over this function draws your score based on your level. In this next function i am calling drawgamescore function, which is in dsip_end_score makro.
int EndOfGame()
{
char key;
//static int state;
int result = 1;
key = KBD_GetKey();
display_msg = DSIP_END_SCORE;
if (key == BTN_OK){
//display_msg = DISP_REFRESH_ALL;
//display_msg = DSIP_END_SCORE;
return result;
}
return result;
}
Here is the main game function
void Game()
{
static int state;
int result;
switch (state)
{
case 1: //waiting for the game start
result = WaitForStart();
if (result == 1) state++;
break;
case 2: //Play the game
result = PlayTheGame();
if (result == 1) state++;
break;
case 3: //Display the score
result = EndOfGame();
if (result == 1) state=0;
break;
default: //0 or unknown value: reset the game
state = 1;
break;
}
}
Thanks.
I tried
int EndOfGame()
{
char key;
static int state;
int result = 1;
key = KBD_GetKey();
display_msg = DSIP_END_SCORE;
if (key == BTN_OK){
//display_msg = DISP_REFRESH_ALL;
//display_msg = DSIP_END_SCORE;
return result;
}
return result;
}
/*
display_msg = DSIP_END_SCORE;
if (key != 0){
switch (key)
{
case BTN_OK:
return result;
break;
}
}
*/
/*
switch (state)
{
case 0:
display_msg = DSIP_END_SCORE;
state++;
break;
case 1:
key = KBD_GetKey();
if (key != 0){
switch (key)
{
case BTN_OK:
return result;
break;
}
break;
}
}
return result;
*/
//display_msg = DISP_REFRESH_ALL;
//display_msg = DSIP_END_SCORE;
//return result;
/*
char key;
int result=0;
//static int state;
key = KBD_GetKey();
if (KBD_isKeyStatePressed(BTN_OK))
{
display_msg = DSIP_END_SCORE;
result = 1;
} else {
result = 1;
}
//return result;
*/
/*
switch (state){
case 0:
KBD_flush(); //empty buffer
//display_msg = DISP_REFRESH_ALL;
display_msg = DSIP_END_SCORE;
return result;
state++;
break;
case 1:
key = KBD_GetKey(); //kbd read dela background services
if (key == BTN_OK){
//display_msg = DISP_REFRESH_ALL;
display_msg = DSIP_END_SCORE;
return result;
break;
}
break;
}
return result;
*/
/*
key = KBD_GetKey();
if (key == BTN_OK) {
//display_msg = DISP_REFRESH_ALL;
return result;
}else{
display_msg = DISP_REFRESH_ALL;
display_msg = DSIP_END_SCORE;
//TODO: write the program
return result;
}*/
I found a solution!
Here is the code if anyone is interested.
int EndOfGame()
{
int result = 0;
char key;
static uint32_t timeStamp;
static int state = 0;
display_msg = DISP_REFRESH_ALL;
switch (state)
{
case 0: //Show end score
display_msg = DSIP_END_SCORE;
timeStamp = GetSysTick();
state++;
break;
case 1: //read keys after 2 seconds
if (Has_X_MillisecondsPassed(2000, &timeStamp)
{
state++;
KBD_flush();
break;
}
break;
case 2:
key = KBD_GetKey();
if (key != 0)
{
switch (key)
{
case BTN_OK:
state = 0;
result = 1;
break;
}
}
//finish after 10 seconds
if (Has_X_MillisecondsPassed(10000, &timeStamp))
{
result = 1;
state = 0;
break;
}
break;
}
return result;
}
If you want to know about the
Has_X_millisecondsPassed();
function you are welcome to see it in systime.c in the File list hyperlink in the question above. For the reference i'm using AtMega328pb microcontroller.

Comments(/*...*/) longer than one line

I am supposed to count the /*...*/ comments in a file and I was wondering if this code is right or am I missing something out?
My Code
void commentsLongerThanOneLine(FILE* inputStream, FILE* outputStream) {
int count = 0, c, state = 1;
while ((c = fgetc(inputStream) != EOF)) {
switch (state) {
case 1: switch (c) {
case '/': state = 2; break;
}
break;
case 2: switch (c) {
case '/': state = 3; break;
case '*': state = 4; break;
default: state = 1;
}
break;
case 3: switch (c) {
case '\n': state = 1; break;
default: state = 4; count++;
}
break;
case 4:switch (c) {
case'*': if (c == '\n') count++; break;
default: state = 4; if (c == '\n') count++;
}
}
}
fprintf(outputStream, "Comments longer than one line: %d\n", count);
}

Variable is printed properly right before an if else loop, but does not retain that value one in the if else loop

I've written a program that reads an account value from a text file and then assigns these values to a variable for each account. Once this is done, reading from the same text file, an action to be done to each account value is identified in the format "Account# Actiontype ActionModifier". All the correct values are being scanned and the proper values are being stored when I insert printfs to check, but immediately after the correct value is printed, the value is put through an else if loop. When doing this for some reason the value is being read as 1 no matter what and is executing the actions in the else if loop as if it were equal to 1.
loopState = 1;
while(loopState != 0)
{
for(i = 1;i < 100 ;i++)
{
if(i < 6)// This executes fine
{
fscanf(bankfile,"%f",&accValue);
switch(i)
{
case 1:
acc1 = accValue;
break;
case 2:
acc2 = accValue;
break;
case 3:
acc3 = accValue;
break;
case 4:
acc4 = accValue;
break;
case 5:
acc5 = accValue;
printf("Done module one\n");
break;
}
}
else // scan for the the first value, than the second, then the third
{
fscanf(bankfile,"%d",&accNum);
if(accNum != 0)
{
fscanf(bankfile,"%c",&accAction);
if(accAction == 'W' || accAction == 'D')
{
fscanf(bankfile,"%f",&actValue);
printf("%d %c %.2f\n",accNum,accAction,actValue);//this will be correct
printf("%d\n",accNum); //this will print say "2"
if(accNum = 1)//but this if statement will be run
{//thus printing the below printf
printf("If accNum = 1 this will print\n");
switch(accAction)
{
case 'W':
final1 = withdrawl(acc1,actValue);
break;
case 'D':
final1 = deposit(acc1,actValue);
break;
}
}
else if(accNum = 2)
{
switch(accAction)
{
case 'W':
final2 = withdrawl(acc2,actValue);
break;
case 'D':
final2 = deposit(acc2,actValue);
break;
}
}
else if(accNum = 3)
{
switch(accAction)
{
case 'W':
final3 = withdrawl(acc3,actValue);
break;
case 'D':
final3 = deposit(acc3,actValue);
break;
}
}
else if(accNum = 4)
{
switch(accAction)
{
case 'W':
final4 = withdrawl(acc4,actValue);
break;
case 'D':
final4 = deposit(acc4,actValue);
break;
}
}
else if(accNum = 5)
{
switch(accAction)
{
case 'W':
final5 = withdrawl(acc5,actValue);
break;
case 'D':
final5 = deposit(acc5,actValue);
break;
}
}
}
else if(accAction == 'B' || accAction == 'U')
{
printf("%d %c\n",accNum,accAction);//this will be correct
printf("%d\n",accNum);//this will print say "4"
if(accNum = 1)//but this if statement will be run
{//thus printing this printf below
printf("If accNum = 1 this will print\n");
switch(accAction)
{
case 'B':
final1 = balance(acc1);
break;
case 'U':
final1 = update(acc1);
break;
}
}
else if(accNum = 2)
{
switch(accAction)
{
case 'B':
final2 = balance(acc2);
break;
case 'U':
final2 = update(acc2);
break;
}
}
else if(accNum = 3)
{
switch(accAction)
{
case 'B':
final3 = balance(acc3);
break;
case 'U':
final3 = update(acc3);
break;
}
}
else if(accNum = 4)
{
switch(accAction)
{
case 'B':
final4 = balance(acc4);
break;
case 'U':
final4 = update(acc4);
break;
}
}
else if(accNum = 5)
{
switch(accAction)
{
case 'B':
final5 = withdrawl(acc5,actValue);
break;
case 'U':
final5 = deposit(acc5,actValue);
break;
}
}
}
}
else
loopState = 0;
}
}
}
printf("Exited Loop");
}
From my understanding I can't see where the value is being altered if just the line before it is being seen as the correct value
Your conditional statements are doing assignment.
else if (accNum = 3)
should be
else if (accNum == 3)

c error: case label does not reduce to an integer constant

This is the switch case concerned by the error:
switch(event.type)
{
case SDL_Quit:
for (int i=0;i<NUMMENU;i++)
SDL_FreeSurface(menus[i]);
return 1;
case SDL_MOUSEMOTION:
x=event.motion.x;
y=event.motion.y;
for(int i=0;i<NUMMENU;i++)
{
if(x>=position[i].x && x<=position[i].x+position[i].w && y>=position[i].y && y<=position[i].y+position[i].h)
{
if(!selected[i])
{
selected[i]=1;
SDL_FreeSurface(menus[i]);
menus[i]=TTF_RenderText_Solid(font,labels[i],color[1]);
}
}else{
if(selected[i])
{
selected[i]=0;
SDL_FreeSurface(menus[i]);
menus[i]=TTF_RenderText_Solid(font,labels[i],color[0]);
}
}
}
case SDL_MOUSEBUTTONDOWN:
x=event.button.x;
y=event.button.y;
for(int i=0;i<NUMMENU;i++)
if(x>=position[1].x && x<=position[1].x+position[i].w && y>=position[i].y && y<=position[i].y+position[i].h)
{
for(int j=0;j<NUMMENU;j++)
SDL_FreeSurface(menus[j]);
return i;
}
break;
case SDL_KEYDOWN:
if(event.key.keysym.sym==SDLK_ESCAPE)
{
for(int i=0;i<NUMMENU;i++)
SDL_FreeSurface(menus[i]);
return 0;
}
}
I have this error and I haven't any idea of why and what should I do to resolve this. I have tried to add break; at the end of each case but no results.
If you need more code or further information, I can give precisions.
Regards,
You are using the function void SDL_Quit(void) rather than the SDL_QUIT event type at line 3.
case SDL_Quit:
^^^^^^^^
for (int i=0;i<NUMMENU;i++)
SDL_FreeSurface(menus[i]);
return 1;
Your case labels such as SDL_Quit/SDL_MOUSEMOTION... could not be integer constants. For example its valid if they are characters labels but not something like const char * string literals which are not integer constants.

Resources