Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » get all pressed keys? (part two)

This thread is locked; no one can reply to it. rss feed Print
get all pressed keys? (part two)
Shadowblitz16
Member #16,818
March 2018

sorry for the new post but my old one was locked for some reason.

is there a way to read keyboard up and down events and mouse up and down events outside of main without needing to pass a handle to the display?

I want to make a simple 6 functions without needing to update them in main..

#SelectExpand
1bool is_keyboard_key_down(int key); 2bool is_keyboard_key_held(int key); 3bool is_keyboard_key_up (int key); 4 5bool is_mouse_button_down(int btn) 6bool is_mouse_button_held(int btn) 7bool is_mouse_button_up (int btn)

is there a easy way to do this?

EDIT: I think this might be able to be done with threads but I am afraid to use them due to mutex locks.

Elias
Member #358
May 2000

You could use global variables. Something like:

#SelectExpand
1int key_down[ALLEGRO_KEY_MAX]; 2bool key_held[ALLEGRO_KEY_MAX]; 3int key_up[ALLEGRO_KEY_MAX]; 4 5void after_game_tick) { 6 for (int i = 0; i < ALLEGRO_KEY_MAX; i++) { 7 key_down[i] = 0; 8 key_up[i] = 0; 9 } 10} 11 12void on_event_key_down(int key) { 13 key_down[key]++; 14 key_held[key] = true; 15} 16 17void on_event_key_up(int key) { 18 key_up[key]++; 19 key_held[key] = false; 20} 21 22bool is_keyboard_key_down(int key) { return key_down[key] > 0; } 23bool is_keyboard_key_held(int key) { return key_held[key]; } 24bool is_keyboard_key_up(int key) { return key_up[key] > 0; }

Call the two event functions when you receive a key up/down event in main. Call the after_game_tick function when you're done handling game input to reset the down/up counters.

Exactly the same will work for mouse.

--
"Either help out or stop whining" - Evert

Edgar Reynaldo
Member #8,592
May 2007
avatar

torhu
Member #2,727
September 2002
avatar

Your old topic wasn't locked. You just can't double post.

Could mention the trick to get around that: Edit the post, preferreably putting "APPEND:" or similiar before the additions, then click on Send to top ;)

Edgar Reynaldo
Member #8,592
May 2007
avatar

torhu
Member #2,727
September 2002
avatar

I meant that I could :p

Shadowblitz16
Member #16,818
March 2018

@Elias
is there a way to implement this so I don't have to handler the events in the main loop?
I was thinking something like a simple init function.

@Edgar Reynaldo and @torhu

sorry I didn't realize that.
does APPEND notify users of the topic that it has updated?

bamccaig
Member #7,536
July 2006
avatar

Elias
Member #358
May 2000

The way I do it is I have an init() function and tick() function for the game and do everything there (and the actual main loop inside of main() does nothing but handling the Allegro events).

--
"Either help out or stop whining" - Evert

Shadowblitz16
Member #16,818
March 2018

@bamccaig awesome i will keep that in mind.
@Elias so is it possible to handle events for my gui in tick without a display?
and if so is it possiable to do it so I can use the same events for another module?

Edgar Reynaldo
Member #8,592
May 2007
avatar

For now, you have to have a window to get input. Because that's where Windows sends you the input. There's no way around it.

Please explain what you are trying to do.

Rodolfo Lam
Member #16,045
August 2015

It seems that the OP is having a case of the “XY Problem”. He is asking about an attempted solution rather than his actual problem.

In other words, he is trying to solve a problem X. He really thinks solution Y will work. Now, instead of asking about X, he is asking about Y.

Can you start from 0 and tell us what you want to do? I saw a red flag when you mentioned threads. Most code doesn’t need threads at all. You also said modules. Are you trying to abstract Allegro into different components or something like that? The more information and code you provide, the more likely someone here will give you a solution.

Audric
Member #907
January 2001

Examples are often made as single file / function, but I understand the issue is about organizing the code in different modules (C files).

The main event loop, wherever it is, could include this part : (Adapted from Edgar's earlier example)

#SelectExpand
1 do 2 { 3 ALLEGRO_EVENT e; 4 al_wait_for_event(q , &e); 5 (...) 6 if (e.type == ALLEGRO_EVENT_KEY_DOWN) // 7 { // 8 input_notify(&e); // 9 } // This part communicates with input.c 10 if (e.type == ALLEGRO_EVENT_KEY_UP) // 11 { // 12 input_notify(&e); // 13 } // 14 (...) 15 } while (!al_is_event_queue_empty(q));

input.c:

#SelectExpand
1// 'private' 2int mykeys[ALLEGRO_KEY_MAX]; 3 4void input_init() 5{ 6 // clear mykeys[] using memset or whatever 7} 8 9void input_notify(ALLEGRO_EVENT *evt) // < this 10{ 11 // examine the event and update the keyboard state 12 if (e.type == ALLEGRO_EVENT_KEY_DOWN) 13 { 14 mykeys[e.keyboard.keycode] = 1; 15 } 16 if (e.type == ALLEGRO_EVENT_KEY_UP) 17 { 18 mykeys[e.keyboard.keycode] = 0; 19 } 20} 21 22int input_is_key_down(ALLEGRO_KEY k) 23{ 24 // examine the keyboard state, return 0 or 1 25 return mykeys[e.keyboard.keycode]; 26}

input.h:

// the declaration of all the above methods
// mykeys is *not* declared here, because other modules don't need to know about it

Shadowblitz16
Member #16,818
March 2018

so I wrote this yesterday. however I can't test it since it's in a dll project and I can't figure out how to link it into my executable

#SelectExpand
1//app.h 2#pragma once 3#include <allegro5\allegro.h> 4#include <algorithm> 5#include <vector> 6namespace 7{ 8 int _w = 0; 9 int _h = 0; 10 int _fps = 60; 11 const char* _text = "untitled"; 12 bool _visible = false; 13 ALLEGRO_DISPLAY* _display = nullptr; 14 ALLEGRO_EVENT_QUEUE* _queue = nullptr; 15 ALLEGRO_TIMER* _timer = nullptr; 16 17} 18namespace pure { 19namespace app { 20 21 Event init; 22 Event tick; 23 Event draw; 24 Event free; 25 26 int getW() 27 { 28 return _w; 29 } 30 int getH() 31 { 32 return _h; 33 } 34 int getFPS() 35 { 36 return _fps; 37 } 38 39 void run(int w=256, int h=240, const char* text = "untitled", int fps=60) 40 { 41 al_init(); 42 43 _w = w; 44 _h = h; 45 _fps = fps; 46 _text = text; 47 48 init.invoke(); 49 50 bool running = true; 51 while (running) 52 { 53 if (_visible) al_flip_display(); 54 55 ALLEGRO_EVENT event; 56 al_wait_for_event(_queue, &event); 57 58 switch (event.type) 59 { 60 case ALLEGRO_EVENT_DISPLAY_CLOSE: 61 running = false; 62 break; 63 case ALLEGRO_EVENT_TIMER: 64 tick.invoke(); 65 draw.invoke(); 66 break; 67 } 68 } 69 free.invoke(); 70 } 71 72 void show() 73 { 74 _display = al_create_display(_w, _h); 75 _queue = al_create_event_queue(); 76 _timer = al_create_timer(1.0f / _fps); 77 78 al_set_window_title(_display, _text); 79 80 al_register_event_source(_queue, al_get_display_event_source(_display)); 81 al_register_event_source(_queue, al_get_timer_event_source(_timer)); 82 83 _visible = true; 84 } 85 86 struct Event 87 { 88 private: 89 std::vector<void(*)()> functions; 90 91 public: 92 void invoke() 93 { 94 for (int i = 0; i < functions.size(); i++) 95 { 96 if (functions[i] != nullptr) functions[i](); 97 else functions.erase(std::remove(functions.begin(), functions.end(), functions[i]), functions.end()); 98 } 99 } 100 void operator +=(void(*function)()) 101 { 102 functions.push_back(function); 103 } 104 void operator -=(void(*function)()) 105 { 106 functions.erase(std::remove(functions.begin(), functions.end(), function), functions.end()); 107 } 108 }; 109}}

#SelectExpand
1///inp.h 2#pragma once 3#include <allegro5\allegro.h> 4#include "app.h" 5namespace 6{ 7 bool initalized = false; 8 9 //keyboard 10 int curr_keys[ALLEGRO_KEY_MAX]; 11 int prev_keys[ALLEGRO_KEY_MAX]; 12 13 //mouse 14 int curr_curs[16]; 15 int prev_curs[16]; 16 17 void tick() 18 { 19 if (!initalized) return; 20 21 ALLEGRO_KEYBOARD_STATE k_state; 22 al_get_keyboard_state(&k_state); 23 for (int i = 0; i < ALLEGRO_KEY_MAX; i++) 24 { 25 prev_keys[i] = curr_keys[i]; 26 curr_keys[i] = al_key_down(&k_state, i); 27 } 28 29 ALLEGRO_MOUSE_STATE m_state; 30 al_get_mouse_state(&m_state); 31 for (int i = 0; i < ALLEGRO_KEY_MAX; i++) 32 { 33 prev_curs[i] = curr_curs[i]; 34 curr_curs[i] = al_mouse_button_down(&m_state, i); 35 } 36 } 37} 38 39namespace pure { 40namespace inp { 41 42 void init() 43 { 44 al_install_keyboard(); 45 al_install_mouse(); 46 47 //pure::app::tick is a Event which is struct around a vector of function pointers 48 pure::app::tick += tick; 49 initalized = true; 50 } 51 52 bool is_key_down(int key) 53 { 54 return !prev_keys && curr_keys; 55 } 56 bool is_key_held(int key) 57 { 58 return prev_keys && curr_keys; 59 } 60 bool is_key_up (int key) 61 { 62 return prev_keys && !curr_keys; 63 } 64 65 bool is_mouse_down(int key) 66 { 67 return !prev_curs && curr_curs; 68 } 69 bool is_mouse_held(int key) 70 { 71 return prev_curs && curr_curs; 72 } 73 bool is_mouse_up (int key) 74 { 75 return prev_curs && !curr_curs; 76 } 77}}

MikiZX
Member #17,092
June 2019

I cannot test this either though one thing seems to be wrong - namely, second source file, at line 31:

for (int i = 0; i < ALLEGRO_KEY_MAX; i++)

I believe you should change ALLEGRO_KEY_MAX to a variable that your would set in your program's initialization part using the function call that Edgar suggested here: https://www.allegro.cc/forums/thread/617983

Edgar Reynaldo
Member #8,592
May 2007
avatar

MikiZX, nope. ALLEGRO_KEY_MAX is a constant that doesn't change. It's perfectly safe to use.

MikiZX
Member #17,092
June 2019

There are two 'for' loops in Shadowblitz's source, one after the other. The first one is for the keys while the second one is for the mouse buttons. It seems the second loop is the one that accesses an array of 16 elements using an index well out of bounds - sorry, I should have explained it better in my previous post.

torhu
Member #2,727
September 2002
avatar

so I wrote this yesterday. however I can't test it since it's in a dll project and I can't figure out how to link it into my executable

You need to split it into header files and implementation (*.cpp) files. Function definitions go in the implementation files. Class/struct declarations, function prototypes, symbolic constants, typedefs, etc. go in the headers.

Then you just add these files to your game project, which should be configured to build an executable. You don't need to create DLL's unless you have a specific reason to want that level of separation.

Also, you don't really need multiple levels of namespaces in a small project, it's just more to type.

Edgar Reynaldo
Member #8,592
May 2007
avatar

Oh, MikiZX, you're right, sorry I can't read. No, you definitely don't want to check ALLEGRO_KEY_MAX mouse buttons.

bamccaig
Member #7,536
July 2006
avatar

torhu said:

You need to split it into header files and implementation (*.cpp) files. Function definitions go in the implementation files. Class/struct declarations, function prototypes, symbolic constants, typedefs, etc. go in the headers.

https://wiki.allegro.cc/index.php?title=Header_file

Doctor Cop
Member #16,833
April 2018
avatar

This is something good, I would like to bookmark it.

And... I just did.

Go to: