ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY fired outside edge of display
OnlineCop

Setup: Allegro 5.2.2.1 installed into Visual Studio 2015 via NuGet: https://www.nuget.org/packages/Allegro/ an a 64-bit Windows 7.

TL;DR I believe that ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY is being incorrectly fired while the mouse is outside the window but is moving over its edge.

I extended the tutorial code from https://wiki.allegro.cc/index.php?title=Allegro_5_Tutorial/Input to include both mouse-enter and mouse-leave functionality. Essentially, the bouncer will bounce from wall to wall while no mouse is over the window:
{"name":"610949","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/7\/e\/7eac12146bffadc87b1e2153871c9572.png","w":816,"h":638,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/7\/e\/7eac12146bffadc87b1e2153871c9572"}610949

When the mouse is inside the window, the ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY event is called, and the bouncer follows the mouse and its position is displayed on the 2nd line:
{"name":"610952","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/4\/f\/4ff62701ca38ec2fa14e2b1be8d5c7b7.png","w":816,"h":638,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/4\/f\/4ff62701ca38ec2fa14e2b1be8d5c7b7"}610952

Moving the mouse back off the window fires the ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY event, which allows the bouncer to wall-bounce again.

Around the edge of the window is a 5-pixel "resize" edge. My screen is 800x600, and if my mouse is exactly x=800, ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY is fired. If my mouse moves anywhere between x=801 to x=805, the ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY event is fired a second time. But moving my mouse totally off the window (x=806 and further), no ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY is called a second time, meaning that my mouse is still "holding" the bouncer in place.
{"name":"610953","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/3\/0\/305a0d92a3b8480d840274f7a694e4f2.png","w":816,"h":638,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/3\/0\/305a0d92a3b8480d840274f7a694e4f2"}610953

#SelectExpand
1#include <allegro5/allegro.h> 2#include <allegro5/allegro_font.h> 3#include <iostream> 4#include <string> 5#include <sstream> 6 7int InitializeAllegro(ALLEGRO_DISPLAY*&, ALLEGRO_FONT*&, ALLEGRO_TIMER*&, ALLEGRO_EVENT_QUEUE*&); 8 9const double FPS = 60.0; 10const int SCREEN_W = 800; 11const int SCREEN_H = 600; 12 13template<typename T> 14class TVector2 15{ 16public: 17 TVector2() : x(T()), y(T()) {} 18 TVector2(T InX, T InY) : x(InX), y(InY) {} 19 20 TVector2 operator+=(const TVector2& other) 21 { 22 x += other.x; 23 y += other.y; 24 return *this; 25 } 26 27 T x; 28 T y; 29}; 30 31class FBouncer 32{ 33public: 34 FBouncer(const int Width, const int Height, const float StartingX, const float StartingY) 35 : _size(TVector2<int>(Width, Height)) 36 , _position(TVector2<float>(StartingX - Width/2.0, StartingY - Height/2.0)) 37 , _bitmap(nullptr) 38 , _bIsControlled(false) 39 { } 40 41 ~FBouncer() 42 { 43 al_destroy_bitmap(_bitmap); 44 _bitmap = nullptr; 45 } 46 47 TVector2<int> GetSize() const { return _size; } 48 TVector2<float> GetPosition() const { return _position; } 49 TVector2<float> GetDirection() const { return _direction; } 50 ALLEGRO_BITMAP* GetBitmap() { return _bitmap; } 51 52 void SetPosition(const TVector2<float>& InPosition) 53 { 54 _position.x = InPosition.x; 55 _position.y = InPosition.y; 56 } 57 58 void SetPositionCentered(const TVector2<float>& InPosition) 59 { 60 _position.x = InPosition.x - _size.x / 2.0; 61 _position.y = InPosition.y - _size.y / 2.0; 62 } 63 64 void SetDirection(const TVector2<float>& InDirection) 65 { 66 _direction.x = InDirection.x; 67 _direction.y = InDirection.y; 68 } 69 70 void SetControlled(bool bIsControlled) 71 { 72 if (_bIsControlled != bIsControlled) 73 { 74 _bIsControlled = bIsControlled; 75 } 76 } 77 78 void Move() 79 { 80 if (!_bIsControlled) 81 { 82 _position.x += _direction.x; 83 _position.y += _direction.y; 84 } 85 } 86 87 int Init(ALLEGRO_BITMAP* CurrentTargetBitmap) 88 { 89 _bitmap = al_create_bitmap(32, 32); 90 if (_bitmap == nullptr) 91 { 92 std::cout << "FBouncer is unable to create ALLEGRO_BITMAP." << std::endl; 93 return 1; 94 } 95 96 al_set_target_bitmap(_bitmap); 97 al_clear_to_color(al_map_rgb(255, 0, 255)); 98 al_set_target_bitmap(CurrentTargetBitmap); 99 100 return 0; 101 } 102 103protected: 104 TVector2<int> _size; 105 TVector2<float> _position; 106 TVector2<float> _direction; 107 ALLEGRO_BITMAP* _bitmap; 108 bool _bIsControlled; 109}; 110 111 112int main(int argc, char** argv) 113{ 114 ALLEGRO_DISPLAY* display = nullptr; 115 ALLEGRO_FONT* font = nullptr; 116 ALLEGRO_TIMER* timer = nullptr; 117 ALLEGRO_EVENT_QUEUE* event_queue = nullptr; 118 119 int init_error = InitializeAllegro(display, font, timer, event_queue); 120 if (init_error != 0) 121 { 122 if (init_error <= -3) 123 { 124 al_destroy_display(display); 125 } 126 if (init_error <= -4) 127 { 128 al_destroy_font(font); 129 } 130 if (init_error <= -5) 131 { 132 al_destroy_timer(timer); 133 } 134 if (init_error <= -6) 135 { 136 al_destroy_event_queue(event_queue); 137 } 138 return init_error; 139 } 140 141 FBouncer bouncer(32, 32, SCREEN_W / 2, SCREEN_H / 2); 142 bouncer.SetDirection(TVector2<float>(-4.0, 4.0)); 143 bouncer.Init(al_get_backbuffer(display)); 144 145 al_register_event_source(event_queue, al_get_display_event_source(display)); 146 al_register_event_source(event_queue, al_get_timer_event_source(timer)); 147 al_register_event_source(event_queue, al_get_mouse_event_source()); 148 149 al_clear_to_color(al_map_rgb(0, 0, 0)); 150 al_flip_display(); 151 152 al_start_timer(timer); 153 154 std::string mouse_pos_msg(""); 155 156 bool b_needs_redraw = false; 157 while (1) 158 { 159 ALLEGRO_EVENT event; 160 al_wait_for_event(event_queue, &event); 161 162 if (event.type == ALLEGRO_EVENT_TIMER) 163 { 164 // Game logic goes in here 165 166 TVector2<float> direction = bouncer.GetDirection(); 167 TVector2<float> current_pos = bouncer.GetPosition(); 168 169 if ((current_pos.x < 0 && direction.x < 0) || 170 (current_pos.x > SCREEN_W - bouncer.GetSize().x && direction.x > 0)) 171 { 172 direction.x = -direction.x; 173 } 174 175 if ((current_pos.y < 0 && direction.y < 0) || 176 (current_pos.y > SCREEN_H - bouncer.GetSize().y && direction.y > 0)) 177 { 178 direction.y = -direction.y; 179 } 180 181 bouncer.SetDirection(direction); 182 bouncer.Move(); 183 b_needs_redraw = true; 184 } 185 else if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) 186 { 187 break; 188 } 189 else if (event.type == ALLEGRO_EVENT_MOUSE_AXES || 190 event.type == ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY) 191 { 192 bouncer.SetControlled(true); 193 TVector2<float> mouse_pos(event.mouse.x, event.mouse.y); 194 bouncer.SetPositionCentered(mouse_pos); 195 std::stringstream ss("Pos: "); 196 ss << event.mouse.x << "," << event.mouse.y; 197 mouse_pos_msg = ss.str(); 198 } 199 else if (event.type == ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY) 200 { 201 bouncer.SetControlled(false); 202 mouse_pos_msg = ""; 203 } 204 else if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) 205 { 206 break; 207 } 208 209 if (b_needs_redraw && al_is_event_queue_empty(event_queue)) 210 { 211 // Redraw logic goes in here 212 213 al_clear_to_color(al_map_rgb(0, 0, 0)); 214 215 al_draw_text(font, al_map_rgb(255, 255, 255), 400, 300, ALLEGRO_ALIGN_CENTER, "Welcome to Allegro 5!"); 216 al_draw_text(font, al_map_rgb(255, 255, 255), 400, 300 + al_get_font_line_height(font), ALLEGRO_ALIGN_CENTER, mouse_pos_msg.c_str()); 217 for (int i = 1; i < argc; i++) 218 { 219 std::cout << "argv[" << i << "] = " << argv[i] << std::endl; 220 al_draw_text(font, al_map_rgb(255, 255, 255), 400, 300 + i * al_get_font_line_height(font), ALLEGRO_ALIGN_CENTER, argv[i]); 221 } 222 223 al_draw_bitmap(bouncer.GetBitmap(), bouncer.GetPosition().x, bouncer.GetPosition().y, 0); 224 225 al_flip_display(); 226 227 b_needs_redraw = false; 228 } 229 } 230 231 al_destroy_timer(timer); 232 al_destroy_event_queue(event_queue); 233 al_destroy_font(font); 234 al_destroy_display(display); 235 236 return 0; 237} 238 239 240int InitializeAllegro(ALLEGRO_DISPLAY*& display, ALLEGRO_FONT*& font, ALLEGRO_TIMER*& timer, ALLEGRO_EVENT_QUEUE*& queue) 241{ 242 if (!al_init()) 243 { 244 std::cout << "Unable to initialize Allegro 5. Shutting down." << std::endl; 245 return -1; 246 } 247 248 // Call all al_init_*_addon() before other functions. 249 al_init_font_addon(); 250 251 if (!al_install_mouse()) 252 { 253 std::cout << "Unable to install the mouse. Shutting down." << std::endl; 254 return -2; 255 } 256 257 display = al_create_display(SCREEN_W, SCREEN_H); 258 if (display == nullptr) 259 { 260 std::cout << "Unable to create ALLEGRO_DISPLAY. Shutting down." << std::endl; 261 return -3; 262 } 263 264 font = al_create_builtin_font(); 265 if (font == nullptr) 266 { 267 std::cout << "Unable to create ALLEGRO_FONT. Shutting down." << std::endl; 268 return -4; 269 } 270 271 timer = al_create_timer(1.0 / FPS); 272 if (timer == nullptr) 273 { 274 std::cout << "Unable to create ALLEGRO_TIMER. Shutting down." << std::endl; 275 return -5; 276 } 277 278 queue = al_create_event_queue(); 279 if (queue == nullptr) 280 { 281 std::cout << "Unable to create ALLEGRO_EVENT_QUEUE. Shutting down." << std::endl; 282 return -6; 283 } 284 285 return 0; 286}

Is this an engine issue, or should I deal with this in code and "simulate" a second ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY event by detecting the actual mouse position in relation to the screen's dimensions?

EDIT:
A fix is to just programmatically ignore invalid mouse positions:

#SelectExpand
189 else if (event.type == ALLEGRO_EVENT_MOUSE_AXES || 190 event.type == ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY) 191 { 192 if (event.mouse.x < 0 || event.mouse.x > SCREEN_W || 193 event.mouse.y < 0 || event.mouse.y > SCREEN_H) 194 { 195 // Ignore it 196 continue; 197 } 198 bouncer.SetControlled(true); 199 TVector2<float> mouse_pos(event.mouse.x, event.mouse.y); 200 bouncer.SetPositionCentered(mouse_pos); 201 std::stringstream ss("Pos: "); 202 ss << event.mouse.x << "," << event.mouse.y; 203 mouse_pos_msg = ss.str(); 204 }

SiegeLord

Bumping so it doesn't get locked. Haven't had time to look at this yet.

Neil Roy

Part of the problem I see is this code current_pos.x > SCREEN_W. The right edge of the screen is SCREEN_W-1, not SCREEN_W. You should have something like current_pos.x >= SCREEN_W.

I haven't examined your code too thuroughly, but that stood out for me. The screen goes from zero to SCREEN_W-1 in the X direction and zero to SCREEN_H-1 in the Y. In this case your screen goes from zero to 799 in the X, and zero to 599 in the Y. If you're testing to see if it is greater than 800, than what happens if it is on 800 in the X, or on 600 in the Y?

OnlineCop

Changing > SCREEN_W to >= SCREEN_W changes nothing about the issue with the allegro event being fired: all it does is make the cube bounce one pixel sooner.

The mouse still fires off the ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY event when it moves over the window edge.

Under the Windows 7 Control Panel: Control Panel\All Control Panel Items\Personalization I changed to another theme which had about a 2-pixel-thick window border. This event is NOT fired when I move around that border.

The default Windows 7 theme (Aero), however, does have this 5-pixel-thick border.

I tried to write this sample code above as platform-agnostic as possible so it could be tested on other systems (Linux, OS X, ...) to rule out whether this was platform and/or theme specific.

Neil Roy
OnlineCop said:

The mouse still fires off the ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY event when it moves over the window edge.

Have you tried the example programs to see if they do the same thing? ex_mouse_focus.exe is a good test, it reports when the mouse goes outside the display and seems to work no problem for me. It only reports when the mouse is over the actual display and not the border.

Also ex_mouse_events.exe also accurately reports the mouse outside the display.

Edit: I noticed in this section of code a potential problem...

else if (event.type == ALLEGRO_EVENT_MOUSE_AXES ||  event.type == ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY) {

...the ball will be mouse controlled under two conditions, entering the display OR ALLEGRO_EVENT_MOUSE_AXES triggers. So, is the mouse axes still firing while the mouse is outside the display? I would think so.

OnlineCop

ex_mouse_focus.exe turns from black to red when the mouse is over it. When the mouse is over that 5-pixel window edge, it displays "Outside either display", which is repeated as I drag my mouse around it. When I move completely off the window, all text output stops; when I move into the window, it becomes red and the console shows the "In display 1, x = ..., y = ..." properly.

ex_mouse_events.exe only updates the mouse coordinates while over the window: it doesn't update anything while I drag over the window edges.

I can separate the ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY from the ALLEGRO_EVENT_MOUSE_AXES events, although I probably need to detect on launch whether the mouse is already over the window, else the ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY event will not get initially fired.

EDIT:

I wasn't able to properly detect whether the mouse was over the window when the display is created, so a work-around had to be used instead. I introduced a b_mouse_in_window and check it, as well as whether the bouncer is controlled, when event.type == ALLEGRO_EVENT_MOUSE_AXES. I update that value when either event.type == ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY or event.type == ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY.

That seems to get rid of the problem with the window borders. Code below if anyone wanted to see the changes to the events.

#SelectExpand
1#include <allegro5/allegro.h> 2#include <allegro5/allegro_font.h> 3#include <iostream> 4#include <string> 5#include <sstream> 6 7int main(int argc, char ** argv); 8 9/** Initialize all Allegro 5 stuff. Returns 0 on success, or a negative value on error. */ 10int AllegroInit(ALLEGRO_DISPLAY*& display, ALLEGRO_FONT*& font, ALLEGRO_TIMER*& timer, ALLEGRO_EVENT_QUEUE*& queue); 11/** Shut down all Allegro 5 stuff. Usually, destroy them in opposite order they were initialized. */ 12void AllegroDeinit(ALLEGRO_DISPLAY*& display, ALLEGRO_FONT*& font, ALLEGRO_TIMER*& timer, ALLEGRO_EVENT_QUEUE*& queue); 13 14const double FPS = 60.0; 15const int SCREEN_W = 800; 16const int SCREEN_H = 600; 17 18 19template<typename T> 20class TVector2 21{ 22public: 23 TVector2() : x(T()), y(T()) {} 24 TVector2(T InX, T InY) : x(InX), y(InY) {} 25 TVector2(const TVector2<T>& other) 26 { 27 x = other.x; 28 y = other.y; 29 } 30 31 TVector2<T>& operator=(const TVector2<T>& other) 32 { 33 if (this != &other) 34 { 35 x = other.x; 36 y = other.y; 37 } 38 return *this; 39 } 40 41 TVector2<T> operator+=(const TVector2& other) 42 { 43 x += other.x; 44 y += other.y; 45 return *this; 46 } 47 48 TVector2<T> operator*(const float scalar) const 49 { 50 TVector2 VectorScalar(this->x * scalar, this->y * scalar); 51 return VectorScalar; 52 } 53 54 TVector2<T> operator+(const float scalar) const 55 { 56 TVector2<T> VectorScalar(this->x + scalar, this->y + scalar); 57 return VectorScalar; 58 } 59 60 TVector2<T> operator-(const float scalar) const 61 { 62 TVector2<T> VectorScalar(this->x - scalar, this->y - scalar); 63 return VectorScalar; 64 } 65 66 TVector2<T> operator+(const TVector2<T>& other) const 67 { 68 TVector2<T> Vector(this->x + other.x, this->y + other.y); 69 return Vector; 70 } 71 72 TVector2<T> operator-(const TVector2<T>& other) const 73 { 74 TVector2<T> Vector(this->x - other.x, this->y - other.y); 75 return Vector; 76 } 77 78 T x; 79 T y; 80}; 81 82 83typedef TVector2<float> FVector2; 84 85 86class FBouncer 87{ 88public: 89 FBouncer(const FVector2& Size, const FVector2& StartingPosition) 90 : _size(Size * 0.5f) 91 , _position(StartingPosition) 92 , _bitmap(nullptr) 93 , _bIsControlled(false) 94 { } 95 96 ~FBouncer() 97 { 98 al_destroy_bitmap(_bitmap); 99 _bitmap = nullptr; 100 } 101 102 FVector2 GetSize() const { return _size * 2.0f; } 103 FVector2 GetPosition() const { return _position; } 104 FVector2 GetDirection() const { return _direction; } 105 bool GetControlled() const { return _bIsControlled; } 106 ALLEGRO_BITMAP* GetBitmap() { return _bitmap; } 107 108 void SetPosition(const FVector2& InPosition) 109 { 110 _position = InPosition; 111 } 112 113 void SetDirection(const FVector2& InDirection) 114 { 115 _direction.x = InDirection.x; 116 _direction.y = InDirection.y; 117 } 118 119 void SetControlled(bool bIsControlled) 120 { 121 if (_bIsControlled != bIsControlled) 122 { 123 _bIsControlled = bIsControlled; 124 } 125 } 126 127 void Move() 128 { 129 if (!_bIsControlled) 130 { 131 _position.x += _direction.x; 132 _position.y += _direction.y; 133 134 // Check whether we need to bounce off the walls. 135 if (_position.x < _top_left_bounds.x) 136 { 137 _direction.x = -_direction.x; 138 _position.x += _top_left_bounds.x - _position.x; 139 } 140 else if (_position.x > _bottom_right_bounds.x) 141 { 142 _direction.x = -_direction.x; 143 _position.x += _bottom_right_bounds.x - _position.x; 144 } 145 146 if (_position.y < _top_left_bounds.y) 147 { 148 _direction.y = -_direction.y; 149 _position.y += _top_left_bounds.y - _position.y; 150 } 151 else if (_position.y > _bottom_right_bounds.y) 152 { 153 _direction.y = -_direction.y; 154 _position.y += _bottom_right_bounds.y - _position.y; 155 } 156 } 157 } 158 159 int Init(ALLEGRO_BITMAP* CurrentTargetBitmap, const FVector2& TopLeftBounds, const FVector2& BottomRightBounds) 160 { 161 _bitmap = al_create_bitmap(_size.x * 2.0f, _size.y * 2.0f); 162 if (_bitmap == nullptr) 163 { 164 std::cout << "FBouncer is unable to create ALLEGRO_BITMAP." << std::endl; 165 return 1; 166 } 167 168 al_set_target_bitmap(_bitmap); 169 al_clear_to_color(al_map_rgb(255, 0, 255)); 170 al_draw_pixel(3.0f + 0.5f, 3.0f + 0.5f, al_map_rgb(0, 0, 255)); 171 al_draw_pixel(3.0f + 0.5f, 4.0f + 0.5f, al_map_rgb(0, 0, 255)); 172 al_draw_pixel(28.0f + 0.5f, 3.0f + 0.5f, al_map_rgb(0, 0, 255)); 173 al_draw_pixel(28.0f + 0.5f, 4.0f + 0.5f, al_map_rgb(0, 0, 255)); 174 al_set_target_bitmap(CurrentTargetBitmap); 175 176 // Adjusting the bounds instead of calculating x/y offsets from the center 177 // simplifies the math. 178 _top_left_bounds = TopLeftBounds + _size; 179 _bottom_right_bounds = BottomRightBounds - _size; 180 181 return 0; 182 } 183 184 void Draw() 185 { 186 al_draw_bitmap(_bitmap, _position.x - _size.x, _position.y - _size.y, 0); 187 } 188 189protected: 190 /* Size is actually 1/2 the size requested, since object origin is the center, not upper-left corner. */ 191 FVector2 _size; 192 FVector2 _top_left_bounds; 193 FVector2 _bottom_right_bounds; 194 FVector2 _position; 195 FVector2 _direction; 196 bool _bIsControlled; 197 ALLEGRO_BITMAP* _bitmap; 198}; 199 200 201/** Returns < 0 on Allegro init errors, > 0 on gameplay errors, or 0 on success. */ 202int main(int argc, char** argv) 203{ 204 ALLEGRO_DISPLAY* display = nullptr; 205 ALLEGRO_FONT* font = nullptr; 206 ALLEGRO_TIMER* timer = nullptr; 207 ALLEGRO_EVENT_QUEUE* event_queue = nullptr; 208 209 int init_error = AllegroInit(display, font, timer, event_queue); 210 if (init_error != 0) 211 { 212 AllegroDeinit(display, font, timer, event_queue); 213 return init_error; 214 } 215 216 al_register_event_source(event_queue, al_get_display_event_source(display)); 217 al_register_event_source(event_queue, al_get_timer_event_source(timer)); 218 al_register_event_source(event_queue, al_get_mouse_event_source()); 219 220 al_clear_to_color(al_map_rgb(0, 0, 0)); 221 al_flip_display(); 222 223 al_start_timer(timer); 224 225 FBouncer* bouncer = new FBouncer(FVector2(32.0f, 32.0f), FVector2(SCREEN_W / 2, SCREEN_H / 2)); 226 if (bouncer == nullptr) 227 { 228 AllegroDeinit(display, font, timer, event_queue); 229 std::cout << "Unable to create Bouncer. Shutting down." << std::endl; 230 return 1; 231 } 232 bouncer->SetDirection(FVector2(-4.0, 4.0)); 233 bouncer->Init(al_get_backbuffer(display), FVector2(0, 0), FVector2(SCREEN_W, SCREEN_H)); 234 235 std::string mouse_pos_msg(""); 236 237 // HACK! Eww, eww, eww. 238 bool b_mouse_in_window = true; 239 bool b_needs_redraw = false; 240 while (1) 241 { 242 ALLEGRO_EVENT event; 243 al_wait_for_event(event_queue, &event); 244 245 if (event.type == ALLEGRO_EVENT_TIMER) 246 { 247 b_needs_redraw = true; 248 249 // Game logic goes here... 250 bouncer->Move(); 251 } 252 else if (event.type == ALLEGRO_EVENT_DISPLAY_CLOSE) 253 { 254 break; 255 } 256 else if (event.type == ALLEGRO_EVENT_MOUSE_AXES) 257 { 258 if (b_mouse_in_window && !bouncer->GetControlled()) 259 { 260 bouncer->SetControlled(true); 261 } 262 if (bouncer->GetControlled()) 263 { 264 FVector2 mouse_pos(event.mouse.x, event.mouse.y); 265 bouncer->SetPosition(mouse_pos); 266 std::stringstream ss("Pos: "); 267 ss << event.mouse.x << "," << event.mouse.y; 268 mouse_pos_msg = ss.str(); 269 } 270 } 271 else if (event.type == ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY) 272 { 273 b_mouse_in_window = true; 274 bouncer->SetControlled(true); 275 mouse_pos_msg = ""; 276 } 277 else if (event.type == ALLEGRO_EVENT_MOUSE_LEAVE_DISPLAY) 278 { 279 b_mouse_in_window = false; 280 bouncer->SetControlled(false); 281 mouse_pos_msg = ""; 282 } 283 else if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) 284 { 285 break; 286 } 287 288 if (b_needs_redraw && al_is_event_queue_empty(event_queue)) 289 { 290 // Redraw logic goes in here 291 292 al_clear_to_color(al_map_rgb(0, 0, 0)); 293 294 al_draw_text(font, al_map_rgb(255, 255, 255), 400, 300, ALLEGRO_ALIGN_CENTER, "Welcome to Allegro 5!"); 295 al_draw_text(font, al_map_rgb(255, 255, 255), 400, 300 + al_get_font_line_height(font), ALLEGRO_ALIGN_CENTER, mouse_pos_msg.c_str()); 296 for (int i = 1; i < argc; i++) 297 { 298 std::cout << "argv[" << i << "] = " << argv[i] << std::endl; 299 al_draw_text(font, al_map_rgb(255, 255, 255), 400, 300 + i * al_get_font_line_height(font), ALLEGRO_ALIGN_CENTER, argv[i]); 300 } 301 302 bouncer->Draw(); 303 304 al_flip_display(); 305 306 b_needs_redraw = false; 307 } 308 } 309 310 delete bouncer; 311 bouncer = nullptr; 312 313 AllegroDeinit(display, font, timer, event_queue); 314 315 return 0; 316} 317 318 319int AllegroInit(ALLEGRO_DISPLAY*& display, ALLEGRO_FONT*& font, ALLEGRO_TIMER*& timer, ALLEGRO_EVENT_QUEUE*& queue) 320{ 321 if (!al_init()) 322 { 323 std::cout << "Unable to initialize Allegro 5. Shutting down." << std::endl; 324 return -1; 325 } 326 327 // Call all al_init_*_addon() before other functions. 328 al_init_font_addon(); 329 330 if (!al_install_mouse()) 331 { 332 std::cout << "Unable to install the mouse. Shutting down." << std::endl; 333 return -2; 334 } 335 336 display = al_create_display(SCREEN_W, SCREEN_H); 337 if (display == nullptr) 338 { 339 std::cout << "Unable to create ALLEGRO_DISPLAY. Shutting down." << std::endl; 340 return -3; 341 } 342 343 font = al_create_builtin_font(); 344 if (font == nullptr) 345 { 346 std::cout << "Unable to create ALLEGRO_FONT. Shutting down." << std::endl; 347 return -4; 348 } 349 350 timer = al_create_timer(1.0 / FPS); 351 if (timer == nullptr) 352 { 353 std::cout << "Unable to create ALLEGRO_TIMER. Shutting down." << std::endl; 354 return -5; 355 } 356 357 queue = al_create_event_queue(); 358 if (queue == nullptr) 359 { 360 std::cout << "Unable to create ALLEGRO_EVENT_QUEUE. Shutting down." << std::endl; 361 return -6; 362 } 363 364 return 0; 365} 366 367void AllegroDeinit(ALLEGRO_DISPLAY*& display, ALLEGRO_FONT*& font, ALLEGRO_TIMER*& timer, ALLEGRO_EVENT_QUEUE*& queue) 368{ 369 al_destroy_event_queue(queue); 370 al_destroy_timer(timer); 371 al_destroy_font(font); 372 al_destroy_display(display); 373 374 if (al_is_mouse_installed()) 375 { 376 al_uninstall_mouse(); 377 } 378}

I just wish that I could get rid of that nasty b_mouse_in_window check within the loop. Like just check the mouse position before I enter `while (1) { ... }` and set the bouncer->SetControlled() value there.

Thread #616965. Printed from Allegro.cc