Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Stored mouse and keyboard after dialog

Credits go to Edgar Reynaldo, Gideon Weems, pkrcel, and SiegeLord for helping out!
This thread is locked; no one can reply to it. rss feed Print
Stored mouse and keyboard after dialog
Auradrummer
Member #15,778
October 2014

Hello Masters,

I'm with a problem that I'm not finding the answer anywhere.
I'm not a newbie in programming, so if have some good technical explanation I'll appreciate.

The question is simple, I made a hotkey to exit my application. If I cancel the exiting confirmation, the prompt is shown again, as the keys is "stored" in the buffer.

Another thing I've noticed, if I call the exit by clicking at the button (and cancel after), the mouse stays "clicking" even if I release the left button. I need to click anywhere to reset the button.

How can I treat this?

SiegeLord
Member #7,827
October 2006
avatar

Err... is this Allegro4 or Allegro5?

"For in much wisdom is much grief: and he that increases knowledge increases sorrow."-Ecclesiastes 1:18
[SiegeLord's Abode][Codes]:[DAllegro5]:[RustAllegro]

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

You should post the code you are using for your hotkey detection. Use <code>code goes here...</code> tags in the forum.

It sounds like you are using the key array in Allegro 4 and you need a way to tell your application not to go into the prompt again, so toggle a flag off each time you activate a screen, and only turn the flag on when your key state goes from false to true (ie. once).

Auradrummer
Member #15,778
October 2014

Hi masters,

I forgot to post the version, is Allegro 5.

  if(closeButton->isPressed() || (al_key_down(key, ALLEGRO_KEY_Q) && al_key_down(key, ALLEGRO_KEY_LSHIFT)))
    {
        if(!saved)
        {
            if(al_show_native_message_box(disp, "Close?", "Warning", "Loose unsaved informations?", NULL, ALLEGRO_MESSAGEBOX_OK_CANCEL) == 1)
                return EXIT;
        }
        else
            return EXIT;
    }

As I said before, if I use the keyboard (Shift+Q) or click on the button (closeButton), the prompt is shown. But, the keys and the click remains on the buffer after the dialog is closed. If I use mouse, it remains clicked until I click anywhere again. If I use the keyboard, the message pops over and over again!

pkrcel
Member #14,001
February 2012

How do you poll the key and mouse state?
To me it seems it does not properly reset the polled states....so this might be called over and over with the same state (and that would be why you get the described behaviour).

Seems a problem along the lines Edgar suggested.

I might also add that A5 event system is MUCH better of handling this....or at least I find it more comfortable.

It is unlikely that Google shares your distaste for capitalism. - Derezo
If one had the eternity of time, one would do things later. - Johan Halmén

Gideon Weems
Member #3,925
October 2003

If you use events like ALLEGRO_EVENT_DISPLAY_CLOSE and ALLEGRO_EVENT_KEY_DOWN (or even ALLEGRO_EVENT_KEY_CHAR in this case), I suspect the problem will go away.

Edit: I have fallen out of favor with the markup gods.

Auradrummer
Member #15,778
October 2014

Thanks for the replies, but I'm still stuck here. The problem is:

if(ev.type == ALLEGRO_EVENT_TIMER)
    redraw = true;
if(redraw)// && al_is_event_queue_empty(event_queue))
{
    redraw = false;
    ed -> animate(&ev);
}

The problem is that I have to get the commands inside ev->animate(&ev). But the queue must be emptied to redraw, and if the queue is emptied, the event is gone!

I'm thinking in storing the events in a structure before the redraw and pass it to the function, but there are some simpler manner?

---EDIT---
I made that structure. I'll share de code, can be useful to others:

#SelectExpand
1class keyEvent 2{ 3private: 4 std::vector <int> keys; 5 6public: 7 void addKey(int key); 8 bool isKeyDown(int keyCode); 9}; 10 11void keyEvent::addKey(int key) 12{ 13 keys.push_back(key); 14}; 15 16bool keyEvent::isKeyDown(int keyCode) 17{ 18 int pos = -1; 19 for(int i = 0; i < keys.size(); i++) 20 { 21 if(keys[i] == keyCode) 22 pos = i; 23 } 24 25 if(pos != -1) 26 { 27 keys.erase(keys.begin() + pos); 28 return true; 29 } 30 else 31 return false; 32};

Using it is pretty easy.
Instance the class out of the main loop:

keyEvent * kE = new keyEvent();

Then, place the following line in the main loop:

if(ev.type == ALLEGRO_EVENT_KEY_DOWN)
    kE->addKey(ev.keyboard.keycode);

So, you can pass a pointer to the class to anywhere and get the pressed key by invoking

    if(kE->isKeyDown(ALLEGRO_KEYCODE))
        <<action here>>

Is easy to integrate to any application... I like it ;D

Thanks masters!

Gideon Weems
Member #3,925
October 2003

Actually, there's an even easier way to do it. See the second code box.

Auradrummer
Member #15,778
October 2014

Hello guys,

I'm still with problems with that code. The problem, I identified, is that when we open a dialog box by clicking on a button, the MOUSE_UP event happens in that thread so the mouse state not release it. To allow dragging, I improved my interface class.
I'm sure that have another way, but I'll share my solution. This class supports mouse and keyboard.

#SelectExpand
1//PROTOTYPE 2class keyEvent 3{ 4private: 5 std::vector <int> keys; 6 std::vector <int> mouse; 7 8public: 9 void addKey(int key); 10 void addMouseButton(int mouseState); 11 void removeMouseButton(int mouseState); 12 void clearAll(); 13 bool isKeyDown(int keyCode); 14 bool isMouseButtonDown(int mCode); 15};

#SelectExpand
1//IMPLEMENTATION 2void keyEvent::addKey(int key) 3{ 4 keys.push_back(key); 5}; 6 7void keyEvent::addMouseButton(int mouseState) 8{ 9 mouse.push_back(mouseState); 10}; 11 12void keyEvent::removeMouseButton(int mouseState) 13{ 14 int pos = -1; 15 for(int i = 0; i < mouse.size(); i++) 16 { 17 if(mouse[i] & mouseState) 18 pos = i; 19 } 20 if(pos != -1) 21 mouse.erase(mouse.begin() + pos); 22}; 23 24void keyEvent::clearAll() 25{ 26 mouse.clear(); 27 keys.clear(); 28}; 29 30bool keyEvent::isMouseButtonDown(int mCode) 31{ 32 for(int i = 0; i < mouse.size(); i++) 33 { 34 if(mouse[i] & mCode) 35 return true; 36 } 37 return false; 38}; 39 40bool keyEvent::isKeyDown(int keyCode) 41{ 42 int pos = -1; 43 for(int i = 0; i < keys.size(); i++) 44 { 45 if(keys[i] == keyCode) 46 pos = i; 47 } 48 49 if(pos != -1) 50 { 51 keys.erase(keys.begin() + pos); 52 return true; 53 } 54 else 55 return false; 56};

//AT THE MAIN
    keyEvent * kE = new keyEvent();

    while(run)
    {
        if(ev.type == ALLEGRO_EVENT_KEY_DOWN)
            kE->addKey(ev.keyboard.keycode);

        if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN)
            kE->addMouseButton(ev.mouse.button);

        if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP)
            kE->removeMouseButton(ev.mouse.button);
    }

//USAGE examples
if(kE->isKeyDown(ALLEGRO_KEY_ESCAPE)) //detecting keyboard
    printf("ESC press");

//DIALOG examples
int resp = 0;
resp = al_show_native_message_box(disp, "Warning", "Text", "Continue?", 0, ALLEGRO_MESSAGEBOX_YES_NO);
if(resp == 1)
   printf("Com caixa \n");
else
   printf("Sem caixa \n");
kE->clearAll();

Helped me a lot here. If you need to watch mouse or keyboard inside a class/ function, just pass a pointer and proceed normally.

Thanks for the great help masters.

Go to: