Keyboard input while rendering?
Emily Brace

Hello!

I recently started playing around with keyboard input with Allegro, but I can't get it to work like I want it to...
I want to use it in a menu, so want I want to do is listen for ALLEGRO_KEY_DOWN and when it's triggered, move one step down. No need to listen for ALLEGRO_KEY_UP.
I tried using al_get_next_event, but it won't register it at all and using al_wait_for_event just stops rendering until a key is pressed, which is not what I want.
Also tried following the keyboard tutorial on the wiki, but I can't get it to receive all keyboard inputs for some odd reason.
Not sure what I'm missing...

Thanks! :)

Mark Oates

Can you post some code? :)

Emily Brace

First tried from the example:
This draws everything fine, but keyboard inputs are ignored

#SelectExpand
1ALLEGRO_DISPLAY *display; 2ALLEGRO_EVENT_QUEUE* queue; 3ALLEGRO_TIMER *timer; 4 5bool running = true; 6int pos = 0; 7 8enum MYKEYS { 9 KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT 10}; 11 12bool key[4] = { false, false, false, false }; 13bool redraw = true; 14 15int main() 16{ 17 18al_init(); 19al_install_keyboard(); 20 21display = al_create_display(1280, 720); 22timer = al_create_timer(1.0 / 60); 23 24queue = al_create_event_queue(); 25al_register_event_source(queue, al_get_display_event_source(display)); 26al_register_event_source(queue, al_get_keyboard_event_source()); 27al_register_event_source(queue, al_get_timer_event_source(timer)); 28 29al_start_timer(timer); 30 31while (running) 32{ 33 34al_wait_for_event(queue, &ev); 35 36if (ev.type == ALLEGRO_EVENT_TIMER) 37{ 38 if (key[KEY_DOWN]) 39 pos++; 40 if (key[KEY_UP]) 41 pos--; 42} 43 44if (ev.type == ALLEGRO_EVENT_KEY_DOWN) 45{ 46 switch (ev.keyboard.keycode) 47 { 48 case ALLEGRO_KEY_UP: 49 key[KEY_UP] = true; 50 break; 51 52 case ALLEGRO_KEY_DOWN: 53 key[KEY_DOWN] = true; 54 break; 55 } 56} 57 58if (ev.type == ALLEGRO_EVENT_KEY_DOWN) 59{ 60 switch (ev.keyboard.keycode) 61 { 62 case ALLEGRO_KEY_UP: 63 key[KEY_UP] = false; 64 break; 65 66 case ALLEGRO_KEY_DOWN: 67 key[KEY_DOWN] = false; 68 break; 69 } 70} 71 72if (redraw && al_is_event_queue_empty(queue)) 73{ 74 redraw = false; 75 76 al_clear_to_color(al_map_rgb(50, 150, 220)); 77 al_draw_multiline_text(fontMenu, al_map_rgb(250, 250, 250), 110, 313, al_get_display_width(display), 0, NULL, "Start Game \nOptions \nExit Game"); al_draw_bitmap(imageArrow, 64, 313 + (pos * 32), NULL); 78 79al_flip_display(); 80} 81 82} 83 84}

Mark Oates

I noticed a couple of things:

1)

you have two conditionals for ALLEGRO_EVENT_KEY_DOWN, you probably want one of those to be ALLEGRO_EVENT_KEY_UP.

2)

Towards the bottom you have:

if (redraw && al_is_event_queue_empty(queue))
{
   redraw = false;
   // ...
}

but you never set redraw = true (other than when you initialized it).

Also, if you check out forum's formatting cheetsheat, it will tell you how to wrap your code in <code></code> tags for easier reading :)

Emily Brace

Oh, missed that.
Still, the events themselves are never triggered...

EDIT: Nvm, dunno what I did, but it just decided to randomly work xd
Thanks for the help either way,

Edgar Reynaldo

1)
you have two conditionals for ALLEGRO_EVENT_KEY_DOWN, you probably want one of those to be ALLEGRO_EVENT_KEY_UP.
2)
Towards the bottom you have:

if (redraw && al_is_event_queue_empty(queue))
{
   redraw = false;
   // ...
}

Just to go over what Mark said, if you didn't change that, then every time you get a key down, it will set the key to true in the first condition, and then back to false in the second condition. The keys won't do anything when the timer fires because their value will be false. Also, you should set redraw to true when the timer goes off, so the screen will be redrawn.

If you fixed those, post your updated code so we can take a look.

Welcome to allegro.cc. ;)

Emily Brace

Just ended up skipping the timer altogether and went with this instead:
And thanks xd Have been using Allegro for a while, but haven't checked out the forums until now.

#SelectExpand
1ALLEGRO_EVENT ev; 2while (al_get_next_event(queue, &ev)) 3{ 4 if (ev.type == ALLEGRO_EVENT_KEY_DOWN) 5 { 6 if (ev.keyboard.keycode == ALLEGRO_KEY_UP) 7 keyUp = true; 8 if (ev.keyboard.keycode == ALLEGRO_KEY_DOWN) 9 keyDown = true; 10 if (ev.keyboard.keycode == ALLEGRO_KEY_ENTER) 11 keyEnter = true; 12 if (ev.keyboard.keycode == ALLEGRO_KEY_ESCAPE) 13 keyBack = true; 14 } 15}

Edgar Reynaldo

The only problem with that is that the keys will stay in a 'true' state forever once they are set. If you do use a timer, you need to set the keys to false on a KEY_UP event. That method will work if you only redraw when you get a KEY_DOWN event, but you will probably want timers in the future.

For a partial discussion of timing and event loops, see here (mainly it deals with what to do when your logic takes too long, but it discusses the classic allegro timing loop as well) :

https://www.allegro.cc/forums/thread/616480

Emily Brace

In the beginning of the while (running) loop, I set all keys to false again. Don't know if this is the best way to do it really, but it works.
Also, the reason why I change a bool instead of just changing the pos directly is because I want to accept both keyboard and gamepad inputs.

princeofspace

Most folks seem write their own key/joystick manager to glue allegro's input system to their particular game.

Not sure if this is the best way to do this, but I use a struct like so:

struct HWINPUT
{

    /* key handler arrays */
    int key[ALLEGRO_KEY_MAX];

    /* joystick */
    int js[JOYSTICK_MAX];

};

And then in the main game state loop we use a switch:

#SelectExpand
1 2static bool events(struct HWINPUT *hwinput, const ALLEGRO_EVENT e) 3{ 4 5 /* handle event passed above as e 6 * return false if we're not needing to redraw the screen yet 7 * return true to redraw 8 */ 9 switch(e.type) { 10 11 /* redraw if timer is up -- 60 FPS */ 12 case ALLEGRO_EVENT_TIMER: 13 return true; 14 15 /* game control stuff */ 16 case ALLEGRO_EVENT_KEY_DOWN: 17 hwinput->key[e.keyboard.keycode] = true; 18 break; 19 case ALLEGRO_EVENT_KEY_UP: 20 hwinput->key[e.keyboard.keycode] = false; 21 break; 22 case ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN: 23 hwinput->js[e.joystick.button] = true; 24 break; 25 case ALLEGRO_EVENT_JOYSTICK_BUTTON_UP: 26 hwinput->js[e.joystick.button] = false; 27 break; 28 29 } 30 return false; 31 32}

With pointers you can configure "action" buttons to the memory locations in the HWINPUT struct, thus giving the player the ability to set their own control scheme.

Thread #616511. Printed from Allegro.cc