[Allegro5] Native dialog problems
utz000

Hey folks, I'm having some trouble with the native dialogs add-on, namely the al_show_native_message_box function.

Below is a minimal example that exhibits the problem:

#SelectExpand
1#include <iostream> 2#include <allegro5/allegro.h> 3#include <allegro5/allegro_native_dialog.h> 4 5int main(int argc, char **argv){ 6 7 if (!al_init()) { 8 std::cout << "Allegro initialization failed.\n"; 9 return -1; 10 } 11 12 ALLEGRO_DISPLAY *display; 13 ALLEGRO_TIMER *timer; 14 ALLEGRO_EVENT_QUEUE *queue; 15 ALLEGRO_KEYBOARD_STATE kbd; 16 ALLEGRO_EVENT event; 17 18 if (!al_init_native_dialog_addon()) { 19 std::cout << "Failed to initialize native dialogs.\n"; 20 return -1; 21 } 22 23#ifdef ALLEGRO_GTK_TOPLEVEL 24 al_set_new_display_flags(ALLEGRO_GTK_TOPLEVEL); 25#endif 26 27 display = al_create_display(640, 480); 28 if (!display) { 29 std::cout << "Failed to initialize display.\n"; 30 al_uninstall_system(); 31 return -1; 32 } 33 34 if (!al_install_keyboard()) { 35 std::cout << "Failed to initialize keyboard.\n"; 36 al_destroy_display(display); 37 al_uninstall_system(); 38 return -1; 39 } 40 41 timer = al_create_timer(1.0f/25.0f); 42 if (!timer) { 43 std::cout << "Failed to initialize timer.\n"; 44 al_destroy_display(display); 45 al_uninstall_system(); 46 return -1; 47 } 48 49 queue = al_create_event_queue(); 50 if(!queue) { 51 std::cout << "Failed to initialize timer.\n"; 52 al_destroy_timer(timer); 53 al_destroy_display(display); 54 al_uninstall_system(); 55 return -1; 56 } 57 al_register_event_source(queue, al_get_display_event_source(display)); 58 al_register_event_source(queue, al_get_timer_event_source(timer)); 59 al_start_timer(timer); 60 61 while (true) { 62 63 al_wait_for_event(queue, &event); 64 65 if (event.type == ALLEGRO_EVENT_TIMER) { 66 67 al_get_keyboard_state(&kbd); 68 69 if (al_key_down(&kbd, ALLEGRO_KEY_P)) { 70 71// al_pause_event_queue(queue, true); //nope, doesn't help 72 73 int answer = al_show_native_message_box(display, "Message Box", "", "It'sa me, the dia loco!", 74 nullptr, ALLEGRO_MESSAGEBOX_QUESTION|ALLEGRO_MESSAGEBOX_YES_NO); 75 76 std::cout << "answer: " << answer << "\n"; 77 78// al_pause_event_queue(queue, false); 79// al_flush_event_queue(queue); //nope, doesn't help either 80// al_get_keyboard_state(&kbd); //also no use 81 } 82 } 83 else if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) break; 84 } 85 86 al_destroy_event_queue(queue); 87 al_destroy_timer(timer); 88 al_destroy_display(display); 89 al_uninstall_system(); 90 return 0; 91}

Steps to reproduce the problem:
1) compile and run
2) press "P" to trigger the message box
3) click yes or no -> ok, message box closes
4) now press "P" again
5) click yes or no -> message box closes and immediately reopens from this point on

I'm on Debian, using GTK 3.22 and Allegro 5.2.2, and compiling with g++ and clang++, both of which show the same behaviour.

So, the obvious question is: What am I doing wrong here?

Eric Johnson

I was able to reproduce the issue in Ubuntu 16.04.

One thing that stands out to me is that you're getting the keyboard states manually, rather than registering them via al_register_event_source().

After register keyboard events and checking for said events outside of the timer event, the issue is no longer present. Check it out:

#SelectExpand
1#include <iostream> 2#include <allegro5/allegro.h> 3#include <allegro5/allegro_native_dialog.h> 4 5int main(int argc, char **argv){ 6 7 if (!al_init()) { 8 std::cout << "Allegro initialization failed.\n"; 9 return -1; 10 } 11 12 ALLEGRO_DISPLAY *display; 13 ALLEGRO_TIMER *timer; 14 ALLEGRO_EVENT_QUEUE *queue; 15 //ALLEGRO_KEYBOARD_STATE kbd; 16 ALLEGRO_EVENT event; 17 18 if (!al_init_native_dialog_addon()) { 19 std::cout << "Failed to initialize native dialogs.\n"; 20 return -1; 21 } 22 23#ifdef ALLEGRO_GTK_TOPLEVEL 24 al_set_new_display_flags(ALLEGRO_GTK_TOPLEVEL); 25#endif 26 27 display = al_create_display(640, 480); 28 if (!display) { 29 std::cout << "Failed to initialize display.\n"; 30 al_uninstall_system(); 31 return -1; 32 } 33 34 if (!al_install_keyboard()) { 35 std::cout << "Failed to initialize keyboard.\n"; 36 al_destroy_display(display); 37 al_uninstall_system(); 38 return -1; 39 } 40 41 timer = al_create_timer(1.0f/25.0f); 42 if (!timer) { 43 std::cout << "Failed to initialize timer.\n"; 44 al_destroy_display(display); 45 al_uninstall_system(); 46 return -1; 47 } 48 49 queue = al_create_event_queue(); 50 if(!queue) { 51 std::cout << "Failed to initialize timer.\n"; 52 al_destroy_timer(timer); 53 al_destroy_display(display); 54 al_uninstall_system(); 55 return -1; 56 } 57 al_register_event_source(queue, al_get_display_event_source(display)); 58 al_register_event_source(queue, al_get_timer_event_source(timer)); 59 al_register_event_source(queue, al_get_keyboard_event_source()); 60 al_start_timer(timer); 61 62 while (true) { 63 64 al_wait_for_event(queue, &event); 65 66 if (event.type == ALLEGRO_EVENT_KEY_DOWN) { 67 68 if (event.keyboard.keycode == ALLEGRO_KEY_P) { 69 70 int answer = al_show_native_message_box(display, "Message Box", "", "It'sa me, the dia loco!", 71 nullptr, ALLEGRO_MESSAGEBOX_QUESTION|ALLEGRO_MESSAGEBOX_YES_NO); 72 73 std::cout << "answer: " << answer << "\n"; 74 } 75 } 76 else if (event.type == ALLEGRO_EVENT_TIMER) { 77 78 // 79 } 80 else if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) break; 81 } 82 83 al_destroy_event_queue(queue); 84 al_destroy_timer(timer); 85 al_destroy_display(display); 86 al_uninstall_system(); 87 return 0; 88}

utz000

Thanks for your input, Eric. Unfortunately I need precisely timed keyboard input in my project, and I haven't found a viable way of doing that with ALLEGRO_EVENT_KEY_DOWN/UP/CHAR yet. Is there maybe another work-around?

That aside, do you think this is a bug? If so, I'll open an issue on github, and perhaps a mod could move this thread to the Development board.

Eric Johnson

It seems to me that the keyboard state is stuck on a key being down upon showing the dialog. When I reproduce the issue with your original code and get to the point where the dialog repeats itself, if I return focus onto the window and press "P" again and then click one of the dialog buttons, the dialog closes properly.

So it seems that the keyboard state is getting stuck. I don't know if it's the result of an internal bug or whether or implementation is screwy... Go ahead and open an issue on GitHub and wait to see what others have to say.

Edit

I found a workaround. Each time you check for a key being down, but before showing the dialog, uninstall and then reinstall the keyboard. Let me know if it works for you:

#SelectExpand
1#include <iostream> 2#include <allegro5/allegro.h> 3#include <allegro5/allegro_native_dialog.h> 4 5int main(int argc, char **argv){ 6 7 if (!al_init()) { 8 std::cout << "Allegro initialization failed.\n"; 9 return -1; 10 } 11 12 ALLEGRO_DISPLAY *display; 13 ALLEGRO_TIMER *timer; 14 ALLEGRO_EVENT_QUEUE *queue; 15 ALLEGRO_KEYBOARD_STATE kbd; 16 ALLEGRO_EVENT event; 17 18 if (!al_init_native_dialog_addon()) { 19 std::cout << "Failed to initialize native dialogs.\n"; 20 return -1; 21 } 22 23#ifdef ALLEGRO_GTK_TOPLEVEL 24 al_set_new_display_flags(ALLEGRO_GTK_TOPLEVEL); 25#endif 26 27 display = al_create_display(640, 480); 28 if (!display) { 29 std::cout << "Failed to initialize display.\n"; 30 al_uninstall_system(); 31 return -1; 32 } 33 34 if (!al_install_keyboard()) { 35 std::cout << "Failed to initialize keyboard.\n"; 36 al_destroy_display(display); 37 al_uninstall_system(); 38 return -1; 39 } 40 41 timer = al_create_timer(1.0f/25.0f); 42 if (!timer) { 43 std::cout << "Failed to initialize timer.\n"; 44 al_destroy_display(display); 45 al_uninstall_system(); 46 return -1; 47 } 48 49 queue = al_create_event_queue(); 50 if(!queue) { 51 std::cout << "Failed to initialize timer.\n"; 52 al_destroy_timer(timer); 53 al_destroy_display(display); 54 al_uninstall_system(); 55 return -1; 56 } 57 al_register_event_source(queue, al_get_display_event_source(display)); 58 al_register_event_source(queue, al_get_timer_event_source(timer)); 59 al_start_timer(timer); 60 61 while (true) { 62 63 al_wait_for_event(queue, &event); 64 65 if (event.type == ALLEGRO_EVENT_TIMER) { 66 67 al_get_keyboard_state(&kbd); 68 69 if (al_key_down(&kbd, ALLEGRO_KEY_P)) { 70 71 al_uninstall_keyboard(); 72 73 al_install_keyboard(); 74 75 int answer = al_show_native_message_box(display, "Message Box", "", "It'sa me, the dia loco!", 76 nullptr, ALLEGRO_MESSAGEBOX_QUESTION|ALLEGRO_MESSAGEBOX_YES_NO); 77 78 std::cout << "answer: " << answer << "\n"; 79 } 80 } 81 else if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) break; 82 } 83 84 al_destroy_event_queue(queue); 85 al_destroy_timer(timer); 86 al_destroy_display(display); 87 al_uninstall_system(); 88 return 0; 89}

Another Edit

The above can also be accomplished using al_clear_keyboard_state(), but it's currently a part of the unstable API. You have to define ALLEGRO_UNSTABLE before including the Allegro header files to use the unstable API.

#SelectExpand
1#define ALLEGRO_UNSTABLE 2 3#include <iostream> 4#include <allegro5/allegro.h> 5#include <allegro5/allegro_native_dialog.h> 6 7int main(int argc, char **argv){ 8 9 if (!al_init()) { 10 std::cout << "Allegro initialization failed.\n"; 11 return -1; 12 } 13 14 ALLEGRO_DISPLAY *display; 15 ALLEGRO_TIMER *timer; 16 ALLEGRO_EVENT_QUEUE *queue; 17 ALLEGRO_KEYBOARD_STATE kbd; 18 ALLEGRO_EVENT event; 19 20 if (!al_init_native_dialog_addon()) { 21 std::cout << "Failed to initialize native dialogs.\n"; 22 return -1; 23 } 24 25#ifdef ALLEGRO_GTK_TOPLEVEL 26 al_set_new_display_flags(ALLEGRO_GTK_TOPLEVEL); 27#endif 28 29 display = al_create_display(640, 480); 30 if (!display) { 31 std::cout << "Failed to initialize display.\n"; 32 al_uninstall_system(); 33 return -1; 34 } 35 36 if (!al_install_keyboard()) { 37 std::cout << "Failed to initialize keyboard.\n"; 38 al_destroy_display(display); 39 al_uninstall_system(); 40 return -1; 41 } 42 43 timer = al_create_timer(1.0f/25.0f); 44 if (!timer) { 45 std::cout << "Failed to initialize timer.\n"; 46 al_destroy_display(display); 47 al_uninstall_system(); 48 return -1; 49 } 50 51 queue = al_create_event_queue(); 52 if(!queue) { 53 std::cout << "Failed to initialize timer.\n"; 54 al_destroy_timer(timer); 55 al_destroy_display(display); 56 al_uninstall_system(); 57 return -1; 58 } 59 al_register_event_source(queue, al_get_display_event_source(display)); 60 al_register_event_source(queue, al_get_timer_event_source(timer)); 61 al_start_timer(timer); 62 63 while (true) { 64 65 al_wait_for_event(queue, &event); 66 67 if (event.type == ALLEGRO_EVENT_TIMER) { 68 69 al_get_keyboard_state(&kbd); 70 71 if (al_key_down(&kbd, ALLEGRO_KEY_P)) { 72 73 al_clear_keyboard_state(display); 74 75 int answer = al_show_native_message_box(display, "Message Box", "", "It'sa me, the dia loco!", 76 nullptr, ALLEGRO_MESSAGEBOX_QUESTION|ALLEGRO_MESSAGEBOX_YES_NO); 77 78 std::cout << "answer: " << answer << "\n"; 79 } 80 } 81 else if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) break; 82 } 83 84 al_destroy_event_queue(queue); 85 al_destroy_timer(timer); 86 al_destroy_display(display); 87 al_uninstall_system(); 88 return 0; 89}

utz000

Yes! That does the trick. Thanks a lot!

Was just reading up on al_clear_keyboard_state() as well, but it's only been added in 5.2.3. So I'll probably stick with the first version, since it might be a while before the new stuff finds its way into the various distros that have Allegro in their repos.

Eric Johnson

I'm glad it works for you.

Also, I wouldn't worry too much about newer versions of Allegro finding their way into various distributions, as it's not difficult to manually build Allegro from source. The gist of it is as follows:

sudo apt-get install -y libgl1-mesa-dev libglu1-mesa-dev cmake build-essential make libxcursor-dev cmake g++ freeglut3-dev libxcursor-dev libpng12-dev libjpeg-dev libfreetype6-dev libgtk2.0-dev libasound2-dev libpulse-dev libopenal-dev libflac-dev libdumb1-dev libvorbis-dev libphysfs-dev

git clone https://github.com/liballeg/allegro5
cd allegro5
mkdir build
cd build
cmake ..
make
sudo make install
sudo ldconfig

Thread #617009. Printed from Allegro.cc