Mac OS X Joystick Bug (A5)
Todd Cope

In my current project I allow the player to configure multiple controllers if they have them hooked up. I just tried to play my game with two joysticks on my Mac and noticed that the game froze during initialization.

I tracked the freeze down to a function in hidjoy.m, init_joystick(). In that function there is a do/while loop that never exits. After tinkering with the code I think there is a problem in this function:

#SelectExpand
1static void device_add_callback( 2 void *context, 3 IOReturn result, 4 void *sender, 5 IOHIDDeviceRef ref 6) { 7 int i; 8 9 (void)context; 10 (void)result; 11 (void)sender; 12 13 al_lock_mutex(add_mutex); 14 15 CFTypeRef product_id = get_device_product_id(ref); 16
17 ALLEGRO_JOYSTICK_OSX *joy = find_joystick(product_id);
18 if (joy == NULL) { 19 joy = al_calloc(1, sizeof(ALLEGRO_JOYSTICK_OSX)); 20 joy->product_id = product_id; 21 ALLEGRO_JOYSTICK_OSX **back = _al_vector_alloc_back(&joysticks); 22 *back = joy; 23 } 24 joy->cfg_state = new_joystick_state; 25 26 CFArrayRef elements = IOHIDDeviceCopyMatchingElements( 27 ref, 28 NULL, 29 kIOHIDOptionsTypeNone 30 ); 31 32 add_elements(elements, joy); 33 34 CFRelease(elements); 35 36 // Fill in ALLEGRO_JOYSTICK properties 37 joy->parent.info.num_sticks = joy->num_x_axes; 38 joy->parent.info.num_buttons = joy->num_buttons; 39 for (i = 0; i < joy->num_x_axes; i++) { 40 int axes = 1; 41 if (joy->num_y_axes >= i) 42 axes++; 43 if (joy->num_z_axes >= i) 44 axes++; 45 joy->parent.info.stick[i].num_axes = axes; 46 char *buf = al_malloc(20); 47 sprintf(buf, "Stick %d", i); 48 joy->parent.info.stick[i].name = buf; 49 } 50 51 al_unlock_mutex(add_mutex); 52 53 osx_joy_generate_configure_event(); 54 55 ALLEGRO_INFO("Found joystick (%d buttons, %d %d %d axes)\n", 56 joy->num_buttons, joy->num_x_axes, joy->num_y_axes, joy->num_z_axes); 57}

The highlighted line is the root of the infinite do/while loop. I think because both of my joysticks are the same model, they both have the same ID. The find_joystick() function scans the vector of existing joysticks to see if there is an ID match before adding a new joystick to the vector. Since the IDs are the same, the second joystick is never added to the vector. That's why this code never exits, since the vector never expands to match the number of joysticks stored in the count variable:

   do {
      al_rest(0.001);
      CFSetRef devices = IOHIDManagerCopyDevices(hidManagerRef);
      if (devices == nil) {
         break;
      }
      count = CFSetGetCount(devices);
      CFRelease(devices);
      al_lock_mutex(add_mutex);
      size = _al_vector_size(&joysticks);
      al_unlock_mutex(add_mutex);
   } while (size < count);

After a cursory look at the Apple HID CLass Device Interface Guide my guess is the IOHIDDeviceRef needs to be used to distinguish between joysticks since the string ID can end up being identical for different devices.

Trent Gamblin

If IOHIDDeviceRef is unique it should work. Can you try it? I can try it out tomorrow too assuming my 360 controllers report the same product id (so I can see it fail before testing something that works.)

Todd Cope

I probably won't be able to do it until Saturday. If you don't get to it before then I'll try it.

Trent Gamblin

Do you have any short program that makes good use of dual joysticks? At least maybe you can confirm with your game if this patch works. What I've tested is:

1) Before patch, ex_joystick_events hangs at black screen on startup
2) After patch, ex_joystick_events loads
3) Both joysticks manipulate the knobs and doohickeys in ex_joystick_events

The patch to hidjoy.m is attached.

Todd Cope

I applied your patch and the problem seems to be solved! ex_joystick_events works as you described. Both joysticks can now be used in my game. For good measure I hooked up a third (different) joystick and tried my game with all three and they all three were able to be used.

Trent Gamblin

Just to double check, you're getting 3 different sets of input right? Like controlling 3 characters separately? Most likely the case but just want to make sure.

Todd Cope

Yes. Everything is working perfectly now.

Trent Gamblin

Alright. Thanks for reporting. BTW I did use your suggestion of using the IOHIDDeviceRef as the id.

Todd Cope

Yeah, I saw it in the patch. Glad my idea worked :) Thanks for fixing this.

Trent Gamblin

It's in SVN now.

Arthur Kalliokoski

This makes me feel pretty inside! :D

Thread #608122. Printed from Allegro.cc