Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Inconstistent joystick event delay

This thread is locked; no one can reply to it. rss feed Print
Inconstistent joystick event delay
CaptainVice
Member #13,313
August 2011

I'm getting very inconsistent results when using allegro to get joystick inputs. Even the precompiled example program ex_joystick_events.exe demonstrates the problem. In my test programs the keyboard and mouse inputs are all very responsive and work well but the joystick is often slow. I'm using a dinput logitech controller for testing and have verified it across vista and win 7 and Allegro 5.0.4 and 5.1.8 . It works with other games and furthermore I have used joy2key to turn the joystick inputs into keyboard inputs and that eliminates the lag because allegro is processing the keyboard inputs properly. The hardware is fine.

What I have found through testing is that the joystick events are not being noticed when they happen. The delay can be in the dozens of mS to the point where it skips several frames. If the down press is delayed by a lot, and the release not very much, then they can even appear to occur with no delay. It seems like they're getting stuck in the queue even though the keyboard and mice inputs use the same format and queue but have no problems.

Am I missing something about how to handle joystick inputs? As I said the example code ex_joystick_events.exe shows this symptom. Here is a half baked demo I put together to better visualize and time it. Removing the cout portions doesn't make any difference. The keyboard arrow movements are crisp and responsive while the joystick inputs are laggy and even appear to drop altogether when the delay is really bad. For reference you can use the arrow keys and d-pad to move the block. Only moving right will display the timer number.

#SelectExpand
1#include <stdio.h> 2#include <allegro5/allegro.h> 3#include <allegro5/allegro_image.h> 4#include <allegro5/allegro_opengl.h> 5#include <iostream> 6#include <string.h> 7#include <string> 8#include <Windows.h> 9 10 11using namespace std; 12 const float FPS = 60; 13 const int SCREEN_W = 1280; 14 const int SCREEN_H = 720; 15 const int BOUNCER_SIZE = 32; 16 17 18void event_queue_function(); 19 20 21 enum MYKEYS { 22 KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_1, KEY_2, KEY_3, KEY_4, JOY_STICK_2_LEFT, JOY_STICK_2_RIGHT, JOY_STICK_2_UP, JOY_STICK_2_DOWN, JOY_0_DOWN = 0, JOY_0_UP, JOY_1_DOWN = 1, JOY_1_UP,}; 23 24 int main(int argc, char **argv) 25 { 26 27 HWND consoleWindow = GetConsoleWindow(); 28 SetWindowPos( consoleWindow, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOZORDER ); //SetWindowPos( consoleWindow, ?, X pos, Y pos, ?, ?, SWP_NOSIZE | SWP_NOZORDER ); 29 al_set_new_window_position(600, 400); 30 al_set_new_display_option(ALLEGRO_VSYNC, 1, ALLEGRO_REQUIRE); 31 32 33 ALLEGRO_DISPLAY *display = NULL; 34 ALLEGRO_EVENT_QUEUE *event_queue = NULL; 35 ALLEGRO_TIMER *timer = NULL; 36 ALLEGRO_BITMAP *bouncer = NULL; 37 ALLEGRO_BITMAP *bouncer_2 = NULL; 38 float bouncer_x = SCREEN_W / 2.0 - BOUNCER_SIZE / 2.0; 39 float bouncer_y = SCREEN_H / 2.0 - BOUNCER_SIZE / 2.0; 40 float bouncer_2_x = 100; 41 float bouncer_2_y = 100; 42 43 bool key[8] = { false, false, false, false, false, false, false, false }; 44 bool redraw = true; 45 46 if(!al_init()) { 47 fprintf(stderr, "failed to initialize allegro!\n"); 48 return -1; 49 } 50 51 if(!al_install_keyboard()) { 52 fprintf(stderr, "failed to initialize the keyboard!\n"); 53 return -1; 54 } 55 56 if(!al_install_mouse()) { 57 fprintf(stderr, "failed to initialize the mouse!\n"); 58 return -1; 59 } 60 61 timer = al_create_timer(1.0 / FPS); 62 if(!timer) { 63 fprintf(stderr, "failed to create timer!\n"); 64 return -1; 65 } 66 67 68 if(!al_install_joystick()) { 69 fprintf(stderr, "failed to initialize the joystick!\n"); 70 return -1; 71 } 72 73 74 al_init_image_addon(); 75 76 77 display = al_create_display(SCREEN_W, SCREEN_H); 78 if(!display) { 79 fprintf(stderr, "failed to create display!\n"); 80 al_destroy_timer(timer); 81 return -1; 82 } 83 84 85 86 87 ALLEGRO_BITMAP *dummy_bitmap = NULL; 88 bouncer = al_create_bitmap(BOUNCER_SIZE, BOUNCER_SIZE); 89 90 if(!bouncer) { 91 fprintf(stderr, "failed to create bouncer bitmap!\n"); 92 al_destroy_display(display); 93 al_destroy_timer(timer); 94 return -1; 95 } 96 97 bouncer_2 = al_create_bitmap(BOUNCER_SIZE, BOUNCER_SIZE); 98 if(!bouncer_2) { 99 fprintf(stderr, "failed to create bouncer bitmap!\n"); 100 al_destroy_display(display); 101 al_destroy_timer(timer); 102 return -1; 103 } 104 105 al_set_target_bitmap(bouncer); 106 107 al_clear_to_color(al_map_rgb(255, 0, 255)); 108 109 al_set_target_bitmap(bouncer_2); 110 111 al_clear_to_color(al_map_rgb(0, 255, 255)); 112 113 al_set_target_bitmap(al_get_backbuffer(display)); 114 115 al_set_clipping_rectangle(0, 0, 1280, 720); 116 117 event_queue = al_create_event_queue(); 118 if(!event_queue) { 119 fprintf(stderr, "failed to create event_queue!\n"); 120 al_destroy_bitmap(bouncer); 121 al_destroy_display(display); 122 al_destroy_timer(timer); 123 return -1; 124 } 125 126 al_register_event_source(event_queue, al_get_display_event_source(display)); 127 128 al_register_event_source(event_queue, al_get_timer_event_source(timer)); 129 130 al_register_event_source(event_queue, al_get_mouse_event_source()); 131 132 al_register_event_source(event_queue, al_get_keyboard_event_source()); 133 134 al_register_event_source(event_queue, al_get_joystick_event_source()); 135 136 al_clear_to_color(al_map_rgb(0,0,0)); 137 138 al_flip_display(); 139 140 al_start_timer(timer); 141 142 bool quit = false; 143 bool started = false; 144 145 while (!quit) 146 { 147 double start_time = 0.0; 148 int num_events = 0; 149 do 150 { 151 ALLEGRO_EVENT ev; 152 al_wait_for_event(event_queue, &ev); 153 ++num_events; 154 155 if(ev.type == ALLEGRO_EVENT_TIMER) 156 { 157 158 } 159 160 else if(ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) 161 { 162 quit = true; 163 break; 164 } 165 else if(ev.type == ALLEGRO_EVENT_MOUSE_AXES || ev.type == ALLEGRO_EVENT_MOUSE_ENTER_DISPLAY) 166 { 167 bouncer_x = ev.mouse.x; 168 bouncer_y = ev.mouse.y; 169 170 } 171 else if(ev.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) 172 { 173 } 174 else if(ev.type == ALLEGRO_EVENT_KEY_DOWN) 175 { 176 switch(ev.keyboard.keycode) 177 { 178 case ALLEGRO_KEY_UP: 179 key[KEY_UP] = true; 180 break; 181 182 case ALLEGRO_KEY_DOWN: 183 key[KEY_DOWN] = true; 184 break; 185 186 case ALLEGRO_KEY_LEFT: 187 key[KEY_LEFT] = true; 188 break; 189 190 case ALLEGRO_KEY_RIGHT: 191 key[KEY_RIGHT] = true; 192 cout << "Right key down @ " << al_get_timer_count(timer); 193 break; 194 } 195 } 196 else if(ev.type == ALLEGRO_EVENT_KEY_UP) { 197 switch(ev.keyboard.keycode) { 198 case ALLEGRO_KEY_UP: 199 key[KEY_UP] = false; 200 break; 201 202 case ALLEGRO_KEY_DOWN: 203 key[KEY_DOWN] = false; 204 break; 205 206 case ALLEGRO_KEY_LEFT: 207 key[KEY_LEFT] = false; 208 break; 209 210 case ALLEGRO_KEY_RIGHT: 211 key[KEY_RIGHT] = false; 212 cout << " Right key up @ " << al_get_timer_count(timer) << '\n'; 213 break; 214 215 case ALLEGRO_KEY_ESCAPE: 216 quit = true; 217 break; 218 } 219 } 220 221 222 else if (ev.type == ALLEGRO_EVENT_JOYSTICK_AXIS) 223 { 224 switch(ev.joystick.stick) 225 { 226 227 case 2: // d pad 228 229 if(ev.joystick.axis == 0) 230 { 231 if(ev.joystick.pos >= 0.9) 232 { 233 key[KEY_RIGHT] = true; 234 cout << "Right joy down @ " << al_get_timer_count(timer); 235 } 236 237 if (ev.joystick.pos <= -0.9) 238 { 239 key[KEY_LEFT] = true; 240 } 241 242 if(ev.joystick.pos >= -0.9 && ev.joystick.pos <= 0.9) 243 { 244 key[KEY_RIGHT] = false; 245 key[KEY_LEFT] = false; 246 cout << " Right joy up @ " << al_get_timer_count(timer) << '\n'; 247 } 248 } 249 250 else if(ev.joystick.axis == 1) 251 { 252 if(ev.joystick.pos >= 0.9) 253 { 254 key[KEY_DOWN] = true; 255 } 256 257 if (ev.joystick.pos <= -0.9) 258 { 259 key[KEY_UP] = true; 260 } 261 262 if(ev.joystick.pos >= -0.9 && ev.joystick.pos <= 0.9) 263 { 264 key[KEY_UP] = false; 265 key[KEY_DOWN] = false; 266 } 267 } 268 break; 269 } 270 } 271 272 273else if (ev.type == ALLEGRO_EVENT_JOYSTICK_BUTTON_DOWN) 274 { 275 switch(ev.joystick.button) 276 { 277 278 case JOY_0_DOWN: 279 cout << "BUTTON 0"; 280 key[KEY_UP] = true; 281 282 break; 283 284 case JOY_1_DOWN: 285 cout << "BUTTON 1"; 286 break; 287 288 289 } 290 291 } 292 293 294else if (ev.type == ALLEGRO_EVENT_JOYSTICK_BUTTON_UP) 295 { 296 switch(ev.joystick.button) 297 { 298 299 case 0: 300 key[KEY_UP] = false; 301 break; 302 303 } 304 305 } 306 307 } 308 309 310 311 312 313 314 315//// left = 37, up = 38, right = 39, down = 40 316//bool key_states[256]; 317// 318// 319//for (int i=37;i<41;i++) 320//{ 321// key_states[i] = GetAsyncKeyState(i); 322//} 323// 324//if (key_states[37] == true) 325//{ 326// cout << "left" << '\n'; 327//} 328// 329//if (key_states[38] == true) 330//{ 331// cout << "up" << '\n'; 332//} 333// 334//if (key_states[39] == true) 335//{ 336// cout << "right" << '\n'; 337//} 338// 339//if (key_states[40] == true) 340//{ 341// cout << "down" << '\n'; 342//} 343 344while (!al_is_event_queue_empty(event_queue)); 345 if(al_is_event_queue_empty) 346 { 347 redraw = true; 348 } 349 350 if(key[KEY_UP] && bouncer_2_y >= 4.0) 351 { 352 bouncer_2_y -= 4.0; 353 } 354 355 if(key[KEY_DOWN] && bouncer_2_y <= SCREEN_H - BOUNCER_SIZE - 4.0) 356 { 357 bouncer_2_y += 4.0; 358 } 359 360 if(key[KEY_LEFT] && bouncer_2_x >= 4.0) { 361 bouncer_2_x -= 4.0; 362 } 363 364 if(key[KEY_RIGHT] && bouncer_2_x <= SCREEN_W - BOUNCER_SIZE - 4.0) 365 { 366 bouncer_2_x += 4.0; 367 } 368 369 if (redraw == true) 370 { 371 redraw = false; 372 al_clear_to_color(al_map_rgb(0,0,0)); 373 al_draw_bitmap(bouncer, bouncer_x, bouncer_y, 0); 374 al_draw_bitmap(bouncer_2, bouncer_2_x, bouncer_2_y, 0); 375 376 al_flip_display(); 377 } 378 } 379 380 al_destroy_bitmap(bouncer); 381 al_destroy_bitmap(bouncer_2); 382 al_destroy_timer(timer); 383 al_destroy_display(display); 384 al_destroy_event_queue(event_queue); 385 386 return 0; 387 }

Dizzy Egg
Member #10,824
March 2009
avatar

I don't suppose installing the joystick before creating the timer helps?

----------------------------------------------------
Please check out my songs:
https://soundcloud.com/dont-rob-the-machina

CaptainVice
Member #13,313
August 2011

Moved both the al_install_joystick and al_register_event_source(event_queue, al_get_joystick_event_source()) above the timer creation. No change.

However, I did realize that I'm an idiot because I tested it on two vista machines. Had forgot which laptop was which. Whenever I realized this and switched over to the windows 7 laptop all the joystick functions work properly. No lag, no problem with queues, just as responsive as the keyboard and mouse. The allegro provided examples, my test code, and my game all work fine on win7.

So now I'm scratching my head about why it works with win7 but not 2 vista machines. The controller works correctly with all the games I've played on the vista computers, just not with allegro. It's a logitech dual action G-UF13A that is dinput only. Might be some weird conflict between an old OS, old controller, and allegro. I just ordered one of the newer logitech controllers that can toggle between x and d inputs to see if I can replicate the problem with a different controller and also x input mode.

In the meantime if anybody has a vista machine I'd be curious if they could replicate the problem. You can use my code or the ex_joystick_events allegro sample. I see inconsistent, delayed inputs in both.

beoran
Member #12,636
March 2011

This might be a problem in how Allegro handles dinput joysticks on vista, since I only tested the Windows joystick driver code on a virtualized Windows 7 when I developed it. If you have the time to do so, it would help us greatly if you could help debug this. XInput controllers use a different "driver" and so should not be affected.

CaptainVice
Member #13,313
August 2011

Sure. I'm not really familiar with Allegro development so I might need some help on that end. Let me know what info you need to get started.

beoran
Member #12,636
March 2011

Hmmm, is there any way you could profile your program to see if it doesn't spend too much time in directinput or in allegro's joystick routines? It's easier for me to explain Allegro then to explain how I would debug such a problem.

Dizzy Egg
Member #10,824
March 2009
avatar

Have you got any compiler optimisations turned on??

EDIT: also I noticed in your conditions if the axis is 0.9 then both conditions are me, because you use >= 0.9 and <= 0.9 - your condition to set the movement to false should be < 0.9

----------------------------------------------------
Please check out my songs:
https://soundcloud.com/dont-rob-the-machina

CaptainVice
Member #13,313
August 2011

Beoran - I'll get on that, but I'll be traveling for most of the week so not sure when I'll work on it.

Dizzy - That code is probably a mess in terms of logic and actually doing things. I just threw in some random stuff from other examples, cut out parts, and tested to get a feel for the timing.

Also it is not related to the compiler because even the precompiled example exes that come with some Allegro binaries exhibit the problem. I just frankencoded this to better visualize and understand the problem.

Dizzy Egg
Member #10,824
March 2009
avatar

Cool....also when you set left/right to true, set the other to false!

----------------------------------------------------
Please check out my songs:
https://soundcloud.com/dont-rob-the-machina

Go to: