Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Keycode out of range

This thread is locked; no one can reply to it. rss feed Print
Keycode out of range
ismqdb
Member #23,641
January 2023

Hello everyone,

I've written basic Breakout app in Visual Studio and today I've moved to project to Linux/VS Code. I've managed to get the app to compile with gcc and to work without any modification.

However, every key press throws an seg fault. I've followed Vivace tutorial, which declares an array of allegro_key_max length. The event is then processed in switch statement with allegro_event_key_down and specific value is fetched with array[keyboard.keycode]. But every key press is out of allegro_key_max range. For example, when pressing right arrow, I get keycode value of 1431940368. The same code worked fine on Visual Studio/Windows.

Any advice, anything I'm missing here? Did something change in the meantime?

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

ismqdb
Member #23,641
January 2023

It is already zeroed out. Here's the code:

#SelectExpand
1typedef struct GameObject { 2 ... 3 unsigned char key[ALLEGRO_KEY_MAX]; 4 int done; 5 int redraw; 6 ... 7} GameObject; 8 9void GameLoop(GameObject* gameObject) { 10 al_start_timer(gameObject->timer); 11 12 while (1) 13 { 14 al_wait_for_event(gameObject->eventQueue, gameObject->event); 15 16 al_get_keyboard_state(gameObject->keyboardState); 17 18 switch (gameObject->event->type) 19 { 20 case ALLEGRO_EVENT_TIMER: 21 if (gameObject->key[ALLEGRO_KEY_ENTER]) 22 if (!gameObject->gameRunning) 23 gameObject->gameRunning = true; 24 25 if (!gameObject->gameRunning) 26 break; 27 28 if (gameObject->key[ALLEGRO_KEY_LEFT]) 29 if ((gameObject->rect->x1 - gameObject->rect->dx) > 0) { 30 gameObject->rect->x1 -= gameObject->rect->dx; 31 gameObject->rect->x2 -= gameObject->rect->dx; 32 } 33 if (gameObject->key[ALLEGRO_KEY_RIGHT]) 34 if ((gameObject->rect->x2 + gameObject->rect->dx) < 800) { 35 gameObject->rect->x1 += gameObject->rect->dx; 36 gameObject->rect->x2 += gameObject->rect->dx; 37 } 38 39 if (gameObject->ball->isActive) 40 moveTheBall(gameObject); 41 42 if (gameObject->key[ALLEGRO_KEY_ESCAPE]) 43 gameObject->done = true; 44 45 for (int i = 0; i < ALLEGRO_KEY_MAX; i++) 46 gameObject->key[i] &= KEY_SEEN; 47 48 gameObject->redraw = true; 49 break; 50 51 case ALLEGRO_EVENT_KEY_DOWN: 52 gameObject->key[gameObject->event->keyboard.keycode] = KEY_SEEN | KEY_RELEASED; --> this line throws seg fault 53 break; 54 case ALLEGRO_EVENT_KEY_UP: 55 gameObject->key[gameObject->event->keyboard.keycode] &= KEY_RELEASED; 56 break; 57 case ALLEGRO_EVENT_DISPLAY_CLOSE: 58 gameObject->done = true; 59 break; 60 } // end switch 61 62 if (gameObject->done) 63 break; 64 65 if (gameObject->gameRunning) { 66 ... 67 } 68 else { // game not running 69 ... 70 } 71 } 72}

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Please use <code>code goes here...</code> tags for your code. It looks like event or event->keyboard is uninitialized. Make sure it is a key event before checking the keyboard field. Post full code, there are parts missing. Just attach a zip file to the reply.

#SelectExpand
1 2typedef struct GameObject { 3... 4unsigned char key[ALLEGRO_KEY_MAX]; 5int done; 6int redraw; 7... 8} GameObject; 9 10void GameLoop(GameObject* gameObject) { 11al_start_timer(gameObject->timer); 12 13while (1) 14{ 15al_wait_for_event(gameObject->eventQueue, gameObject->event); 16 17al_get_keyboard_state(gameObject->keyboardState); 18 19switch (gameObject->event->type) 20{ 21case ALLEGRO_EVENT_TIMER: 22if (gameObject->key[ALLEGRO_KEY_ENTER]) 23if (!gameObject->gameRunning) 24gameObject->gameRunning = true; 25 26if (!gameObject->gameRunning) 27break; 28 29if (gameObject->key[ALLEGRO_KEY_LEFT]) 30if ((gameObject->rect->x1 - gameObject->rect->dx) > 0) { 31gameObject->rect->x1 -= gameObject->rect->dx; 32gameObject->rect->x2 -= gameObject->rect->dx; 33} 34if (gameObject->key[ALLEGRO_KEY_RIGHT]) 35if ((gameObject->rect->x2 + gameObject->rect->dx) < 800) { 36gameObject->rect->x1 += gameObject->rect->dx; 37gameObject->rect->x2 += gameObject->rect->dx; 38} 39 40if (gameObject->ball->isActive) 41moveTheBall(gameObject); 42 43if (gameObject->key[ALLEGRO_KEY_ESCAPE]) 44gameObject->done = true; 45 46for (int i = 0; i < ALLEGRO_KEY_MAX; i++) 47gameObject->key[i] &= KEY_SEEN; 48 49gameObject->redraw = true; 50break; 51 52case ALLEGRO_EVENT_KEY_DOWN: 53gameObject->key[gameObject->event->keyboard.keycode] = KEY_SEEN | KEY_RELEASED; --> this line throws seg fault 54break; 55case ALLEGRO_EVENT_KEY_UP: 56gameObject->key[gameObject->event->keyboard.keycode] &= KEY_RELEASED; 57break; 58case ALLEGRO_EVENT_DISPLAY_CLOSE: 59gameObject->done = true; 60break; 61} // end switch 62 63if (gameObject->done) 64break; 65 66if (gameObject->gameRunning) { 67... 68} 69else { // game not running 70... 71} 72} 73}

ismqdb
Member #23,641
January 2023

Yeah, sorry about the formatting.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

ismqdb
Member #23,641
January 2023

I do. I'm getting the size of pointer instead of struct. I've changed it and it is working now.

I was aware of this and this was basically the reason why I switched to Linux. If I recall correctly, Allegro functions request pointers to these structs, hence why I have defined them as pointers. I do remember that Visual Studio didn't let me initialize the pointers with size of struct, rather it wanted size of pointers, that's why I left it like this. It was odd to me but it had me pulling my hair out. Similar thing was happening with initialization of block collection and blocks it contains. But then again, I've might have been mistaken in some way then.

One more question. I am able to init Event and keyboard state with size of structs. If I try the same with other Allegro functionalities (timer, event q, display, font) I get the error that I can't use sizeof on incomplete types. Any advice on how to get around of this problem? I mean, I can leave it as size of pointers but will it have some repercussions in the future?

Thank you for you help.

torhu
Member #2,727
September 2002
avatar

I think I would just allocate and clear GameObject like this:

`GameObject gameObject = { 0 };`

You don't need malloc, free, or memset for this. It's just more code, and more error prone.

Looking at your InitFuncs.c I would remove every single malloc, and have all structs and arrays be inline in GameObject instead. You don't need heap allocation when your data has fixed sizes and a clearly defined lifetime.

Some Allegro types have functions that allocate and destroy them for you, like al_create_timer and al_destroy_timer for ALLLEGRO_TIMER, etc. Then you just store the pointer the creation function returns. Other types, like ALLEGRO_EVENT, require you to allocate the structs, it's often easiest to just put them on the stack.

You should end up with something like this, this is just the struct definitions I changed:

#SelectExpand
1typedef struct { 2 int cx; 3 int cy; 4 int radius; 5 int dx; 6 int dy; 7 unsigned int lives; 8 ALLEGRO_COLOR color; 9 int isActive; 10} Ball; 11 12typedef struct { 13 Block blocks[BLOCK_ROWS][BLOCK_COUNT]; 14 unsigned hardBricksRows; 15 unsigned mediumBricksRows; 16 unsigned softBricksRows; 17} BlockCollection; 18 19typedef struct { 20 Level level[NUM_OF_LEVELS]; 21 BlockCollection blockCollection; 22 unsigned levelCleared; 23} Levels; 24 25typedef struct { 26 Rectangle rect; 27 Ball ball; 28 Levels levels; 29 ALLEGRO_TIMER* timer; 30 ALLEGRO_EVENT_QUEUE* eventQueue; 31 ALLEGRO_DISPLAY* display; 32 ALLEGRO_FONT* font; 33 ALLEGRO_EVENT event; 34 ALLEGRO_KEYBOARD_STATE keyboardState; 35 unsigned char key[ALLEGRO_KEY_MAX]; 36 int done; 37 int redraw; 38 unsigned currentLevel; 39 unsigned score; 40 bool gameRunning; 41} GameObject;

I removed the struct tags, since I don't see the point of having both those and the typedefs. :P

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Something to remember - a pointer may or may not point to actual memory. In your case it pointed to memory, but of the wrong size. It was too small, hence the segfault. VS is giving you bad advice if that is what it told you to do.

Torhu's advice is good. Reduce heap allocation as much as possible and declare things on the stack normally.

ismqdb
Member #23,641
January 2023

Yeah, true. That's why I moved to Linux, less bloat to deal with.

torhu, thank you for pointing it out, I will keep that in mind. I really appreciate the advice.

Polybios
Member #12,293
October 2010

If you run into segfaults / heap / memory issues, on Linux, you can always use the tool "valgrind" to check.

Torhu's advice is good. Reduce heap allocation as much as possible and declare things on the stack normally.

Yes.

If you need to allocate memory on the heap, though, it is preferable to use std::unique_ptr with make_unique. It will automatically destroy the heap-allocated object when itself runs out of scope. But, I'm not sure whether you use C++. :)

ismqdb
Member #23,641
January 2023

At this moment, I mostly do C because it is smaller language. I'm slowly working my way into C++.

When I was writing this app, I just learned pointers properly and this was a way to put that knowledge into practice but it came back to bite me. Same thing happens when I try to do something in C++, I try to stuff everything into a class.

I heard of valgrind but I haven't used it. I'm using clang-tidy for static analysis, coupled with gcc options like -wall and -werror.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

GullRaDriel
Member #3,861
September 2003
avatar

-Wshadow is going to give you an hepta ton +10 of unneeded warning.

Just wanted to place the wording somewhere. The correct expression in French is 'Une tétrachiée plus quinze' but it's somewhat 'loosing it' in the translation.
;D

"Code is like shit - it only smells if it is not yours"
Allegro Wiki, full of examples and articles !!

Go to: