5050#define JOYSTICK_USAGE_NUMBER 0x04
5151#define GAMEPAD_USAGE_NUMBER 0x05
5252
53+ #define JOYSTICK_NAME_MAX 256
54+
5355typedef struct {
5456 ALLEGRO_JOYSTICK parent;
57+ char name[JOYSTICK_NAME_MAX];
5558 IOHIDElementRef buttons[_AL_MAX_JOYSTICK_BUTTONS];
5659 IOHIDElementRef axes[_AL_MAX_JOYSTICK_STICKS][_AL_MAX_JOYSTICK_AXES];
5760 IOHIDElementRef dpad;
@@ -130,12 +133,37 @@ static CFMutableDictionaryRef CreateDeviceMatchingDictionary(
130133 return result;
131134}
132135
133- static ALLEGRO_JOYSTICK_OSX *find_joystick (IOHIDDeviceRef ident)
136+ static bool joystick_uses_element (ALLEGRO_JOYSTICK_OSX *joy, IOHIDElementRef elem)
137+ {
138+ int i, j;
139+
140+ if (elem) {
141+ for (i = 0 ; i < joy->parent .info .num_buttons ; i++) {
142+ if (joy->buttons [i] == elem)
143+ return true ;
144+ }
145+ for (i = 0 ; i < joy->parent .info .num_sticks ; i++) {
146+ for (j = 0 ; j < joy->parent .info .stick [i].num_axes ; j++) {
147+ if (joy->axes [i][j] == elem)
148+ return true ;
149+ }
150+ }
151+ if (joy->dpad == elem)
152+ return true ;
153+ }
154+ else {
155+ return true ;
156+ }
157+
158+ return false ;
159+ }
160+
161+ static ALLEGRO_JOYSTICK_OSX *find_joystick (IOHIDDeviceRef ident, IOHIDElementRef elem)
134162{
135163 int i;
136164 for (i = 0 ; i < (int )_al_vector_size (&joysticks); i++) {
137165 ALLEGRO_JOYSTICK_OSX *joy = *(ALLEGRO_JOYSTICK_OSX **)_al_vector_ref (&joysticks, i);
138- if (ident == joy->ident ) {
166+ if (ident == joy->ident && joystick_uses_element (joy, elem) ) {
139167 return joy;
140168 }
141169 }
@@ -145,10 +173,12 @@ static CFMutableDictionaryRef CreateDeviceMatchingDictionary(
145173
146174static const char *get_element_name (IOHIDElementRef elem, const char *default_name)
147175{
176+ const char *name_cstr = NULL ;
148177 CFStringRef name = IOHIDElementGetName (elem);
149- if (name) {
150- return CFStringGetCStringPtr (name, kCFStringEncodingUTF8 );
151- }
178+ if (name)
179+ name_cstr = CFStringGetCStringPtr (name, kCFStringEncodingUTF8 );
180+ if (name_cstr)
181+ return name_cstr;
152182 else
153183 return default_name;
154184}
@@ -182,31 +212,58 @@ static void add_axis(ALLEGRO_JOYSTICK_OSX *joy, int stick_index, int axis_index,
182212 joy->axes [stick_index][axis_index] = elem;
183213}
184214
185- static void add_elements (CFArrayRef elements, ALLEGRO_JOYSTICK_OSX *joy)
215+ static void add_elements (CFArrayRef elements, ALLEGRO_JOYSTICK_OSX *joy, int device_joystick )
186216{
187- int i;
217+ int i, start_i = 0 ;
188218 char default_name[100 ];
189219 int stick_class = -1 ;
190220 int axis_index = 0 ;
221+ bool collection_started = false ;
222+ int current_joystick = -1 ;
191223
192224 joy_null (joy);
193225
226+ /* look for device_joystick */
194227 for (i = 0 ; i < CFArrayGetCount (elements); i++) {
195228 IOHIDElementRef elem = (IOHIDElementRef)CFArrayGetValueAtIndex (
196229 elements,
197230 i
198231 );
232+ int etype = IOHIDElementGetType (elem);
233+ if (etype == kIOHIDElementTypeCollection ) {
234+ collection_started = true ;
235+ }
236+ else if (etype == kIOHIDElementTypeInput_Button || etype == kIOHIDElementTypeInput_Misc ) {
237+ if (collection_started) {
238+ current_joystick++;
239+ collection_started = false ;
240+ if (current_joystick == device_joystick) {
241+ start_i = i;
242+ break ;
243+ }
244+ }
245+ }
246+ }
247+
248+ for (i = start_i; i < CFArrayGetCount (elements); i++) {
249+ IOHIDElementRef elem = (IOHIDElementRef)CFArrayGetValueAtIndex (
250+ elements,
251+ i
252+ );
199253
200254 int usage = IOHIDElementGetUsage (elem);
255+ if (IOHIDElementGetType (elem) == kIOHIDElementTypeCollection ) {
256+ break ;
257+ }
201258 if (IOHIDElementGetType (elem) == kIOHIDElementTypeInput_Button ) {
202- if (usage >= 0 && usage < _AL_MAX_JOYSTICK_BUTTONS &&
203- !joy->buttons [usage- 1 ]) {
204- joy->buttons [usage- 1 ] = elem;
205- sprintf (default_name, " Button %d " , usage- 1 );
259+ if (usage >= 0 && joy-> parent . info . num_buttons < _AL_MAX_JOYSTICK_BUTTONS &&
260+ !joy->buttons [joy->parent.info.num_buttons ]) {
261+ joy->buttons [joy->parent.info.num_buttons ] = elem;
262+ sprintf (default_name, " Button %d " , joy-> parent . info . num_buttons );
206263 const char *name = get_element_name (elem, default_name);
207264 char *str = al_malloc (strlen (name)+1 );
208265 strcpy (str, name);
209- joy->parent .info .button [usage- 1 ].name = str;
266+ joy->parent .info .button [joy->parent.info.num_buttons ].name = str;
210267 joy->parent .info .num_buttons ++;
211268 }
212269 }
@@ -216,18 +273,33 @@ static void add_elements(CFArrayRef elements, ALLEGRO_JOYSTICK_OSX *joy)
216273 long max = IOHIDElementGetLogicalMax (elem);
217274 int new_stick_class = -1 ;
218275 int stick_index = joy->parent .info .num_sticks - 1 ;
276+ int axis_type = -1 ;
219277
220278 switch (usage) {
221279 case kHIDUsage_GD_X :
280+ new_stick_class = 1 ;
281+ axis_type = 0 ;
282+ break ;
222283 case kHIDUsage_GD_Y :
284+ new_stick_class = 1 ;
285+ axis_type = 1 ;
286+ break ;
223287 case kHIDUsage_GD_Z :
224288 new_stick_class = 1 ;
289+ axis_type = 2 ;
225290 break ;
226291
227292 case kHIDUsage_GD_Rx :
293+ new_stick_class = 2 ;
294+ axis_type = 0 ;
295+ break ;
228296 case kHIDUsage_GD_Ry :
297+ new_stick_class = 2 ;
298+ axis_type = 1 ;
299+ break ;
229300 case kHIDUsage_GD_Rz :
230301 new_stick_class = 2 ;
302+ axis_type = 2 ;
231303 break ;
232304
233305 case kHIDUsage_GD_Hatswitch :
@@ -250,7 +322,19 @@ static void add_elements(CFArrayRef elements, ALLEGRO_JOYSTICK_OSX *joy)
250322 stick_class = new_stick_class;
251323
252324 char *buf = al_malloc (20 );
253- sprintf (buf, " Stick %d " , stick_index);
325+ switch (stick_class) {
326+ case 1 :
327+ sprintf (buf, " Primary Stick" );
328+ break ;
329+ case 2 :
330+ sprintf (buf, " Secondary Stick" );
331+ break ;
332+ case 3 :
333+ sprintf (buf, " Hat Switch" );
334+ break ;
335+ default :
336+ sprintf (buf, " Stick %d " , stick_index);
337+ }
254338 joy->parent .info .stick [stick_index].name = buf;
255339 }
256340 else
@@ -261,14 +345,14 @@ static void add_elements(CFArrayRef elements, ALLEGRO_JOYSTICK_OSX *joy)
261345 joy->dpad = elem;
262346
263347 joy->dpad_axis_horiz = axis_index;
264- sprintf (default_name, " Axis %i " , axis_index );
348+ sprintf (default_name, " X- Axis" );
265349 char *str = al_malloc (strlen (default_name)+1 );
266350 strcpy (str, default_name);
267351 joy->parent .info .stick [stick_index].axis [axis_index].name = str;
268352
269353 ++axis_index;
270354 joy->dpad_axis_vert = axis_index;
271- sprintf (default_name, " Axis %i " , axis_index );
355+ sprintf (default_name, " Y- Axis" );
272356 str = al_malloc (strlen (default_name)+1 );
273357 strcpy (str, default_name);
274358 add_axis (joy, stick_index, axis_index, min, max, str, elem);
@@ -277,7 +361,19 @@ static void add_elements(CFArrayRef elements, ALLEGRO_JOYSTICK_OSX *joy)
277361 joy->parent .info .stick [stick_index].num_axes = 2 ;
278362 }
279363 else {
280- sprintf (default_name, " Axis %i " , axis_index);
364+ switch (axis_type) {
365+ case 0 :
366+ sprintf (default_name, " X-Axis" );
367+ break ;
368+ case 1 :
369+ sprintf (default_name, " Y-Axis" );
370+ break ;
371+ case 2 :
372+ sprintf (default_name, " Z-Axis" );
373+ break ;
374+ default :
375+ sprintf (default_name, " Axis %i " , axis_index);
376+ }
281377 const char *name = get_element_name (elem, default_name);
282378 char *str = al_malloc (strlen (name)+1 );
283379 strcpy (str, name);
@@ -298,44 +394,92 @@ static void osx_joy_generate_configure_event(void)
298394 _al_generate_joystick_event (&event);
299395}
300396
397+ static int device_count_joysticks (IOHIDDeviceRef ref)
398+ {
399+ int i;
400+ int count = 0 ;
401+ bool collection_started = false ;
402+
403+ CFArrayRef elements = IOHIDDeviceCopyMatchingElements (
404+ ref,
405+ NULL ,
406+ kIOHIDOptionsTypeNone
407+ );
408+ for (i = 0 ; i < CFArrayGetCount (elements); i++) {
409+ IOHIDElementRef elem = (IOHIDElementRef)CFArrayGetValueAtIndex (
410+ elements,
411+ i
412+ );
413+
414+ int etype = IOHIDElementGetType (elem);
415+ if (etype == kIOHIDElementTypeCollection ) {
416+ collection_started = true ;
417+ }
418+ else if (etype == kIOHIDElementTypeInput_Button || etype == kIOHIDElementTypeInput_Misc ) {
419+ if (collection_started) {
420+ count++;
421+ collection_started = false ;
422+ }
423+ }
424+ }
425+ CFRelease (elements);
426+ return count;
427+ }
428+
429+ static void device_setup_joystick (IOHIDDeviceRef ref, ALLEGRO_JOYSTICK_OSX *joy, int device_joystick)
430+ {
431+ CFStringRef product_name;
432+ joy->cfg_state = new_joystick_state;
433+
434+ CFArrayRef elements = IOHIDDeviceCopyMatchingElements (
435+ ref,
436+ NULL ,
437+ kIOHIDOptionsTypeNone
438+ );
439+
440+ add_elements (elements, joy, device_joystick);
441+ product_name = IOHIDDeviceGetProperty (ref, CFSTR (kIOHIDProductKey ));
442+ if (product_name)
443+ {
444+ CFStringGetCString (product_name, joy->name , JOYSTICK_NAME_MAX, kCFStringEncodingUTF8 );
445+ }
446+ CFRelease (elements);
447+ }
448+
301449static void device_add_callback (
302450 void *context,
303451 IOReturn result,
304452 void *sender,
305453 IOHIDDeviceRef ref
306454) {
455+ int i;
456+ int device_joysticks;
307457 (void )context;
308458 (void )result;
309459 (void )sender;
310460
311461 al_lock_mutex (add_mutex);
312462
313- ALLEGRO_JOYSTICK_OSX *joy = find_joystick (ref);
463+ ALLEGRO_JOYSTICK_OSX *joy = find_joystick (ref, NULL );
314464 if (joy == NULL ) {
315- joy = al_calloc (1 , sizeof (ALLEGRO_JOYSTICK_OSX));
316- joy->ident = ref;
317- ALLEGRO_JOYSTICK_OSX **back = _al_vector_alloc_back (&joysticks);
318- *back = joy;
465+ device_joysticks = device_count_joysticks (ref);
466+ for (i = 0 ; i < device_joysticks; i++) {
467+ joy = al_calloc (1 , sizeof (ALLEGRO_JOYSTICK_OSX));
468+ joy->ident = ref;
469+ ALLEGRO_JOYSTICK_OSX **back = _al_vector_alloc_back (&joysticks);
470+ *back = joy;
471+ device_setup_joystick (ref, joy, i);
472+ ALLEGRO_INFO (" Found joystick (%d buttons, %d sticks)\n " ,
473+ joy->parent .info .num_buttons , joy->parent .info .num_sticks );
474+ }
475+ }
476+ else {
477+ device_setup_joystick (ref, joy, 0 );
319478 }
320- joy->cfg_state = new_joystick_state;
321-
322- CFArrayRef elements = IOHIDDeviceCopyMatchingElements (
323- ref,
324- NULL ,
325- kIOHIDOptionsTypeNone
326- );
327-
328- add_elements (elements, joy);
329-
330- CFRelease (elements);
331-
332479
333480 al_unlock_mutex (add_mutex);
334481
335482 osx_joy_generate_configure_event ();
336-
337- ALLEGRO_INFO (" Found joystick (%d buttons, %d sticks)\n " ,
338- joy->parent .info .num_buttons , joy->parent .info .num_sticks );
339483}
340484
341485static void device_remove_callback (
@@ -432,7 +576,7 @@ static void value_callback(
432576
433577 IOHIDElementRef elem = IOHIDValueGetElement (value);
434578 IOHIDDeviceRef ref = IOHIDElementGetDevice (elem);
435- ALLEGRO_JOYSTICK_OSX *joy = find_joystick (ref);
579+ ALLEGRO_JOYSTICK_OSX *joy = find_joystick (ref, elem );
436580
437581 if (!joy) return ;
438582
@@ -733,8 +877,8 @@ static bool reconfigure_joysticks(void)
733877// FIXME!
734878static const char *get_joystick_name (ALLEGRO_JOYSTICK *joy_)
735879{
736- ( void )joy_;
737- return " Joystick " ;
880+ ALLEGRO_JOYSTICK_OSX *joy = (ALLEGRO_JOYSTICK_OSX * )joy_;
881+ return joy-> name ;
738882}
739883
740884static bool get_joystick_active (ALLEGRO_JOYSTICK *joy_)
0 commit comments