tags:

views:

298

answers:

5

How do I detect a button press on a USB gamepad on OSX 10.5 and higher?

I can't wrap my head around the ridiculously complex HID Manager (even though apparently it was simplified with 10.5), and the code samples at Apple have thousands of lines of code that would take days to understand and isolate what I need, so I'd appreciate if someone posts a simple, and fully coded solution for this isolated problem.


EDIT: so far all answers are links to source code or semi obscure libraries for all kinds of HID devices, which will require more research time than what I'd like to invest on this. I am starting a bounty to get an actual snippet of code that solves this simple problem (using an external library or not).


EDIT POS BOUNTY: thanks to all for you help; but unfortunately the answer that has been automatically selected by the system is not working for me, can't figure out why; and the author has not yet replied to my comments. Any insight would be appreciated, but until a fix is found, anyone looking for resources on this topic should take this answer with a pinch of salt.

+1  A: 

I use Procontroll, but thats a Java library. It's good though.

Nathan
+1  A: 

Perhaps you could look at the source code for MAME OS X? It has good gamepad support.

Ken
+2  A: 

You might try Dave Dribin's DDHidLib.

Peter Hosey
Dave did the Mac MAME port, so this is probably equivalent but better than my suggestion.
Ken
Thanks Peter. Documentation is scarce (if not non existent) for this library, do you know how to use it?
Steph Thirion
No, I don't. (Hello, comment length minimum.)
Peter Hosey
Here's Dave's introductory weblog post. He points to the samples in the project. I understand you'd like a snippet, which is fine, but this doesn't look that bad to me. http://www.dribin.org/dave/blog/archives/2007/03/19/ddhidlib_10/
Ken
It's definitely not bad, it's excellent sample code.
Rob Keniger
But have you guys actually attempted to detect events from a gamepad?
Steph Thirion
+2  A: 

Peter's suggestion of the DDHidLib framework is exactly what you are looking for. The library is well designed and the sample code that comes with the library is pretty self-explanatory.

An implementation of an object that gets all the joysticks/gamepads attached to the system and watches for button presses using DDHidLib would look something like this:

#import <Cocoa/Cocoa.h>
#import <DDHidLib/DDHidLib.h>

@interface JoyStickWatcher : NSObject
{
    NSArray* joySticks;
}
- (void)startWatchingJoysticks;
@end


@implementation JoyStickWatcher
- (void)startWatchingJoysticks
{
    //get an array of all joystick objects
    joySticks = [[DDHidJoystick allJoysticks] retain];

    //become the delegate of all available joystick objects
    [joySticks makeObjectsPerformSelector:@selector(setDelegate:) withObject:self];
}

- (void)dealloc
{
    [joySticks release];
    [super dealloc];
}

//these are the DDHidLib joystick delegate methods related to buttons

- (void)ddhidJoystick:(DDHidJoystick *)joystick buttonDown:(unsigned)buttonNumber
{
    NSLog(@"button number %ld of joystick %p went down",joystick,buttonNumber);
}

- (void)ddhidJoystick:(DDHidJoystick *)joystick buttonUp:(unsigned)buttonNumber
{
    NSLog(@"button number %ld of joystick %p went up",joystick,buttonNumber);
}

@end
Rob Keniger
Have you tested this code on OSX 10.5 and higher? It's not working for me. The joySticks array gets populated correctly, but the ddhidJoystick methods don't get called. I've added NSLog calls to the actual DDHidJoystick ddhidJoystick methods (and all other input methods), and as much as I press all the buttons and move all the sticks, none of the methods ever gets called. I've tried it with a couple of gamepads. They do appear correctly in the joySticks array though.
Steph Thirion
and by DDHidJoystick ddhidJoystick methods I meant:DDHidJoystick ddhidJoystick:buttonDown: and DDHidJoystick ddhidJoystick:buttonUp:
Steph Thirion
+1  A: 

I believe I have solved the problem stated by the original poster with regards to the sample code given:

DDHidJoystick* currentJoystick = [joySticks objectAtIndex: 0]; [currentJoystick startListening];

You must select a joystick and start listening to it. Simple as that! Note that you can replace the 0 with any valid index into the joySticks array, in order to select which joystick you listen to, and I am guessing that you can listen to more than one at a time if you like.

Also note that this (and the above) initialization must be done from a thread which has a run loop. If you are working on native mac os x apps, this isn't a problem, but if you are writing portable code and hope to use POSIX threads, you are going to find that many cocoa objects don't function when created inside a POSIX thread. I have found that you can generally call them safely from any thread once created, but creation must occur on a thread with a run loop. Almost all cocoa objects which work via callback style events, fire those events from the run loop of the thread which creates them.

bmac6502