Jelajahi Sumber

Added partial axis support

Brandon Slack 13 tahun lalu
induk
melakukan
c68ee1c76c
1 mengubah file dengan 337 tambahan dan 168 penghapusan
  1. 337 168
      gameplay/src/PlatformMacOSX.mm

+ 337 - 168
gameplay/src/PlatformMacOSX.mm

@@ -17,6 +17,9 @@
 using namespace std;
 using namespace gameplay;
 
+@class View;
+@class OSXGamepad;
+
 // Default to 720p
 static int __width = 1280;
 static int __height = 720;
@@ -42,23 +45,27 @@ static void* __attachToWindow = NULL;
 static bool __mouseCaptured = false;
 static CGPoint __mouseCapturePoint;
 static bool __cursorVisible = true;
+static View* __view = NULL;
 
-static NSMutableDictionary *__gameGamePads = NULL;
-static NSMutableDictionary *__gamePads = NULL;
+static NSMutableDictionary *__activeGamepads = NULL;
+static NSMutableArray *__gamepads = NULL;
 static IOHIDManagerRef __hidManagerRef = NULL;
 
+// Gamepad Helper Function
+OSXGamepad *gamepadForLocationID(NSNumber *locationID);
+OSXGamepad *gamepadForGameHandle(int gameHandle);
+
 // IOHid Helper Functions
 CFMutableDictionaryRef IOHIDCreateDeviceMatchingDictionary(UInt32 inUsagePage, UInt32 inUsage);
-
 CFStringRef IOHIDDeviceGetStringProperty(IOHIDDeviceRef deviceRef, CFStringRef key);
 int IOHIDDeviceGetIntProperty(IOHIDDeviceRef deviceRef, CFStringRef key);
-void IOHIDAxisXYValue(CFIndex value, CFIndex range, int * outX, int * outY);
 
 // IOHid Callbacks
 static void hidDeviceDiscoveredCallback(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef);
-
 static void hidDeviceRemovalCallback(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef);
-static void HidDeviceValueAvailableCallback(void *inContext, IOReturn inResult,  void *inSender);
+static void hidDeviceValueAvailableCallback(void *inContext, IOReturn inResult,  void *inSender);
+
+
 
 double getMachTimeInMilliseconds()
 {
@@ -73,36 +80,131 @@ double getMachTimeInMilliseconds()
     return ((double)mach_absolute_time() * (double)s_timebase_info.numer) / (kOneMillion * (double)s_timebase_info.denom);
 }
 
-@class View;
 
-@interface OSXGamepadButtonState : NSObject
+@interface OSXGamepadAxis : NSObject
+{
+    IOHIDElementRef e;
+    CFIndex v;
+    CFIndex logMin;
+    CFIndex logMax;
+}
++ gamepadAxisWithAxisElement:(IOHIDElementRef)element;
+- initWithAxisElement:(IOHIDElementRef)element;
+- (IOHIDElementRef)element;
+- (IOHIDElementCookie)cookie;
+- (uint32_t)usage;
+- (uint32_t)usagePage;
+- (CFIndex)logicalMinimum;
+- (CFIndex)logicalMaximum;
+
+- (float)calibratedValue;
+- (CFIndex)value;
+- (void)setValue:(CFIndex)value;
+@end
+@implementation OSXGamepadAxis
++ gamepadAxisWithAxisElement:(IOHIDElementRef)element
+{
+    return [[[[self class] alloc] initWithAxisElement:element] autorelease];
+}
+- initWithAxisElement:(IOHIDElementRef)element
+{
+    if((self = [super init]))
+    {
+        e = (IOHIDElementRef)CFRetain(element);
+    }
+}
+- (void)dealloc
+{
+    CFRelease(e);
+    [super dealloc];
+}
+- (IOHIDElementRef)element
+{
+    return e;
+}
+- (IOHIDElementCookie)cookie
+{
+    return IOHIDElementGetCookie(e);
+}
+- (uint32_t)usage
+{
+    return IOHIDElementGetUsage(e);
+}
+- (uint32_t)usagePage
+{
+    return IOHIDElementGetUsagePage(e);
+}
+
+- (CFIndex)logicalMinimum
+{
+    return IOHIDElementGetLogicalMin(e);    
+}
+- (CFIndex)logicalMaximum
+{
+    return IOHIDElementGetLogicalMax(e);
+}
+- (float)calibratedValue
+{
+    return 0.0f;
+}
+- (CFIndex)value
 {
-    IOHIDElementCookie cookie;
+    return v;
+}
+- (void)setValue:(CFIndex)value
+{
+    v = value;
+}
+@end
+
+@interface OSXGamepadButton : NSObject
+{
+    IOHIDElementRef e;
     bool state;
 }
-+ gamepadButtonStateWithCookie:(IOHIDElementCookie)cookie;
-- initWithCookie:(IOHIDElementCookie)cookie;
++ gamepadButtonWithButtonElement:(IOHIDElementRef)element;
+- initWithButtonElement:(IOHIDElementRef)element;
+- (IOHIDElementRef)element;
 - (IOHIDElementCookie)cookie;
+- (uint32_t)usage;
+- (uint32_t)usagePage;
 - (bool)state;
 - (void)setState:(bool)state;
 @end
-@implementation OSXGamepadButtonState
-+ gamepadButtonStateWithCookie:(IOHIDElementCookie)cookie
+@implementation OSXGamepadButton
++ gamepadButtonWithButtonElement:(IOHIDElementRef)element
 {
-    return [[[[self class] alloc] initWithCookie:cookie] autorelease];
+    return [[[[self class] alloc] initWithButtonElement:element] autorelease];
 }
-- initWithCookie:(IOHIDElementCookie)c
+- initWithButtonElement:(IOHIDElementRef)element
 {
     if((self = [super init]))
     {
-        cookie = c;
+        e = (IOHIDElementRef)CFRetain(element);
         state = false;
     }
     return self;
 }
+- (void)dealloc
+{
+    CFRelease(e);
+    [super dealloc];
+}
+- (IOHIDElementRef)element
+{
+    return e;
+}
 - (IOHIDElementCookie)cookie
 {
-    return cookie;
+    return IOHIDElementGetCookie(e);
+}
+- (uint32_t)usage
+{
+    return IOHIDElementGetUsage(e);
+}
+- (uint32_t)usagePage
+{
+    return IOHIDElementGetUsagePage(e);
 }
 - (bool)state
 {
@@ -119,17 +221,16 @@ double getMachTimeInMilliseconds()
     IOHIDDeviceRef hidDeviceRef;
     IOHIDQueueRef queueRef;
     NSMutableArray *buttons;
-    NSMutableArray *axis;
-    NSMutableArray *buttonStates;
+    NSMutableArray *axes;
 }
 @property (assign) IOHIDDeviceRef hidDeviceRef;
 @property (assign) IOHIDQueueRef queueRef;
 @property (retain) NSMutableArray *buttons;
-@property (retain) NSMutableArray *axis;
-@property (retain) NSMutableArray *buttonStates;
+@property (retain) NSMutableArray *axes;
 
 - initWithDevice:(IOHIDDeviceRef)rawDevice;
 - (IOHIDDeviceRef)rawDevice;
+- (NSNumber*)locationID;
 
 - (void)initializeGamepadElements;
 - (bool)startListening;
@@ -142,10 +243,12 @@ double getMachTimeInMilliseconds()
 - (int)vendorID;
 - (int)productID;
 
-- (NSUInteger)numberOfAxis;
+- (NSUInteger)numberOfAxes;
+- (NSUInteger)numberOfSticks;
 - (NSUInteger)numberOfButtons;
 - (NSUInteger)numberOfTriggers;
-- (bool)stateOfButton:(int)buttonIndex;
+- (OSXGamepadAxis*)axisAtIndex:(NSUInteger)index;
+- (OSXGamepadButton*)buttonAtIndex:(NSUInteger)index;
 @end
 
 @implementation OSXGamepad
@@ -153,15 +256,16 @@ double getMachTimeInMilliseconds()
 @synthesize hidDeviceRef;
 @synthesize queueRef;
 @synthesize buttons;
-@synthesize buttonStates;
-@synthesize axis;
+@synthesize axes;
 
-- initWithDevice:(IOHIDDeviceRef)rawDevice {
-    if((self = [super init])) {
+- initWithDevice:(IOHIDDeviceRef)rawDevice
+{
+    if((self = [super init]))
+    {
         [self setButtons:[NSMutableArray array]];
-        [self setAxis:[NSMutableArray array]];
-        [self setButtonStates:[NSMutableArray array]];
+        [self setAxes:[NSMutableArray array]];
 
+        CFRetain(rawDevice);
         [self setHidDeviceRef:rawDevice];
         [self setQueueRef:IOHIDQueueCreate(CFAllocatorGetDefault(), [self hidDeviceRef], 10, kIOHIDOptionsTypeNone)];
         
@@ -170,61 +274,70 @@ double getMachTimeInMilliseconds()
     }
     return self;
 }
-- (void)dealloc {
+- (void)dealloc
+{
     [self stopListening];
+    
+    CFRelease([self rawDevice]);
     CFRelease([self queueRef]);
     [self setQueueRef:NULL];
     [self setHidDeviceRef:NULL];
     
     [self setButtons:NULL];
-    [self setAxis:NULL];
-    [self setButtonStates:NULL];
-    
+    [self setAxes:NULL];
     [super dealloc];
 }
-- (IOHIDDeviceRef)rawDevice {
+- (IOHIDDeviceRef)rawDevice
+{
     return [self hidDeviceRef];
 }
+- (NSNumber*)locationID
+{
+    return (NSNumber*)IOHIDDeviceGetProperty([self rawDevice], CFSTR(kIOHIDLocationIDKey));
+}
 
-- (void)initializeGamepadElements {
+- (void)initializeGamepadElements
+{
     CFArrayRef elements = IOHIDDeviceCopyMatchingElements([self rawDevice], NULL, kIOHIDOptionsTypeNone);
-    for(int i = 0; i < CFArrayGetCount(elements); i++) {
+    for(int i = 0; i < CFArrayGetCount(elements); i++)
+    {
         IOHIDElementRef hidElement = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i);
         IOHIDElementType type = IOHIDElementGetType(hidElement);
-        IOHIDElementCookie hidElementCookie = IOHIDElementGetCookie(hidElement);
-        
-        //uint32_t page = IOHIDElementGetUsagePage( hidElement );
-        //uint32_t usage = IOHIDElementGetUsage( hidElement );
-        //NSLog(@"Type: %d (%X) -- %x - %x", type, type, page, usage);
-        
-        if (type == kIOHIDElementTypeInput_Misc ||
-            type == kIOHIDElementTypeInput_Axis) {
-            [[self axis] addObject:(id)hidElement];
+
+        if (type == kIOHIDElementTypeInput_Misc || type == kIOHIDElementTypeInput_Axis)
+        {
+            uint32_t pageUsage = IOHIDElementGetUsagePage(hidElement);
+
+            switch(pageUsage)
+            {
+                case kHIDUsage_GD_X:
+                case kHIDUsage_GD_Y:
+                case kHIDUsage_GD_Z:
+                case kHIDUsage_GD_Rx:
+                case kHIDUsage_GD_Ry:
+                case kHIDUsage_GD_Rz:
+                {
+                    OSXGamepadAxis *axis = [OSXGamepadAxis gamepadAxisWithAxisElement:hidElement];
+                    [[self axes] addObject:axis];
+                }
+                    break;
+                default:
+                    // Ignore the pointers
+                    // Not: Some of the pointers are for the 6-axis accelerometer in a PS3 controller
+                    break;
+            }
         }
-        if(type == kIOHIDElementTypeInput_Button) {
+        if(type == kIOHIDElementTypeInput_Button)
+        {
+            OSXGamepadButton *button = [OSXGamepadButton gamepadButtonWithButtonElement:hidElement];
             [[self buttons] addObject:(id)hidElement];
-            [[self buttonStates] addObject:[OSXGamepadButtonState gamepadButtonStateWithCookie:hidElementCookie]];
         }
-        /*
-         if(page == 1) {
-            CFArrayRef children = IOHIDElementGetChildren(hidElement);
-            if(children) {
-                for(int k = 0; k < CFArrayGetCount(children); k++) {
-                    IOHIDElementRef childHid = (IOHIDElementRef)CFArrayGetValueAtIndex(children, k);
-                    IOHIDElementType ctype = IOHIDElementGetType(childHid);
-                    uint32_t cpage = IOHIDElementGetUsagePage(childHid);
-                    uint32_t cusage = IOHIDElementGetUsage(childHid);
-                    NSLog(@"\t Child Type: %d (%X) -- %x - %x", ctype, ctype, cpage, cusage);
-                }
-            }
-         }
-         */
-    }
-    
 
+    }
 }
 
-- (bool)startListening {
+- (bool)startListening
+{
     IOReturn kr = IOHIDDeviceOpen([self hidDeviceRef], kIOHIDOptionsTypeNone);
     if(kr != 0) {
         return false;
@@ -232,10 +345,11 @@ double getMachTimeInMilliseconds()
     IOHIDDeviceScheduleWithRunLoop([self hidDeviceRef], CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
     
     IOHIDQueueStart([self queueRef]);
-    IOHIDQueueRegisterValueAvailableCallback([self queueRef], HidDeviceValueAvailableCallback, self);
+    IOHIDQueueRegisterValueAvailableCallback([self queueRef], hidDeviceValueAvailableCallback, self);
     
     CFArrayRef elements = (CFArrayRef)[self watchedElements];
-    for(int i = 0; i < CFArrayGetCount(elements); i++) {
+    for(int i = 0; i < CFArrayGetCount(elements); i++)
+    {
         IOHIDElementRef hidElement = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i);
         IOHIDQueueAddElement([self queueRef], hidElement);
     }
@@ -243,7 +357,8 @@ double getMachTimeInMilliseconds()
     
     return true;
 }
-- (void)stopListening {
+- (void)stopListening
+{
     IOHIDQueueUnscheduleFromRunLoop([self queueRef], CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
     IOHIDQueueStop([self queueRef]);
     
@@ -251,7 +366,8 @@ double getMachTimeInMilliseconds()
     IOHIDDeviceClose([self hidDeviceRef], kIOHIDOptionsTypeNone);
 }
 
-- (NSString *)identifierName {
+- (NSString *)identifierName
+{
     NSString *idName = NULL;
     if(idName == NULL) idName = [self productName];
     if(idName == NULL) idName = [self manufacturerName];
@@ -260,56 +376,78 @@ double getMachTimeInMilliseconds()
     return idName;
 }
 
-- (NSString *)productName {
+- (NSString *)productName
+{
     return (NSString*)IOHIDDeviceGetStringProperty([self rawDevice], CFSTR(kIOHIDProductKey));
 }
-- (NSString *)manufacturerName {
+- (NSString *)manufacturerName
+{
     return (NSString*)IOHIDDeviceGetStringProperty([self rawDevice], CFSTR(kIOHIDManufacturerKey));
 }
-- (NSString *)serialNumber {
+- (NSString *)serialNumber
+{
     return (NSString*)IOHIDDeviceGetStringProperty([self rawDevice], CFSTR(kIOHIDSerialNumberKey));
 }
 
-- (int)vendorID {
+- (int)vendorID
+{
     return IOHIDDeviceGetIntProperty([self rawDevice], CFSTR(kIOHIDVendorIDKey));
 }
-- (int)productID {
+- (int)productID
+{
     return IOHIDDeviceGetIntProperty([self rawDevice], CFSTR(kIOHIDProductIDKey));
 }
 
 
-- (NSUInteger)numberOfAxis {
-    return [[self axis] count];
+- (NSUInteger)numberOfAxes
+{
+    return [[self axes] count];
 }
-- (NSUInteger)numberOfButtons {
+- (NSUInteger)numberOfSticks
+{
+    return ([[self axes] count] / 2);
+}
+- (NSUInteger)numberOfButtons
+{
     return [[self buttons] count];
 }
-- (NSUInteger)numberOfTriggers {
-    return 0;
+- (NSUInteger)numberOfTriggers
+{
+    return 0; // triggers not identified by api - need to manually configure?
 }
-- (bool)stateOfButton:(int)buttonIndex {
-    if([[self buttonStates] count] > buttonIndex)
+- (OSXGamepadAxis*)axisAtIndex:(NSUInteger)index
+{
+    OSXGamepadAxis *a = NULL;
+    if(index < [[self axes] count])
     {
-        OSXGamepadButtonState *bs = [[self buttonStates] objectAtIndex:buttonIndex];
-        return [bs state];
+        a = [[self axes] objectAtIndex:index];
     }
-    return false;
+    return a;
 }
-
-
-
-- (NSArray*)watchedElements {
+- (OSXGamepadButton*)buttonAtIndex:(NSUInteger)index
+{
+    OSXGamepadButton *b = NULL;
+    if(index < [[self buttons] count])
+    {
+        b = [[self buttons] objectAtIndex:index];
+    }
+    return b;
+}
+- (NSArray*)watchedElements
+{
     NSMutableArray *a = [NSMutableArray array];
     [a addObjectsFromArray:[self buttons]];
-    [a addObjectsFromArray:[self axis]];
+    [a addObjectsFromArray:[self axes]];
     return [NSArray arrayWithArray:a];
 }
-- (void)hidValueAvailable:(IOHIDValueRef)value {
+- (void)hidValueAvailable:(IOHIDValueRef)value
+{
     IOHIDElementRef element = IOHIDValueGetElement(value);
 	IOHIDElementCookie cookie = IOHIDElementGetCookie(element);
     
-    for(int i = 0; i < [[self axis] count]; i++) {
-        IOHIDElementRef sElement = (IOHIDElementRef)[[self axis] objectAtIndex:i];
+    /*for(int i = 0; i < [[self axes] count]; i++)
+    {
+        IOHIDElementRef sElement = (IOHIDElementRef)[[self axes] objectAtIndex:i];
         IOHIDElementCookie sCookie = IOHIDElementGetCookie(sElement);
         if(cookie == sCookie) {
 			if(IOHIDValueGetLength(value) > 4) continue; // ignores odd value that crashes (appears to only be with my PS3 controller, not with my Gamepad PC
@@ -324,23 +462,27 @@ double getMachTimeInMilliseconds()
             NSLog(@"Value: %d, %d", x, y);
             break;
         }
+    }*/
+    
+    for(OSXGamepadAxis *a in [self axes])
+    {
+        if([a cookie] == cookie)
+        {
+            CFIndex integerValue = IOHIDValueGetIntegerValue(value);
+            [a setValue:integerValue];
+        }
     }
     
-    for(int i = 0; i < [[self buttons] count]; i++) {
-        IOHIDElementRef bElement = (IOHIDElementRef)[[self buttons] objectAtIndex:i];
-        IOHIDElementCookie bCookie = IOHIDElementGetCookie(bElement);
-        if(cookie == bCookie) {
-            for(OSXGamepadButtonState *bs in [self buttonStates])
-            {
-                if([bs cookie] == bCookie)
-                {
-                    bool pressed = IOHIDValueGetIntegerValue(value);
-                    [bs setState:pressed];
-                }
-            }
+    for(OSXGamepadButton *b in [self buttons])
+    {
+        if([b cookie] == cookie)
+        {
+            bool pressed = IOHIDValueGetIntegerValue(value);
+            [b setState:pressed];
             break;
         }
     }
+
 }
 
 
@@ -360,7 +502,6 @@ double getMachTimeInMilliseconds()
 
 @end
 
-static View* __view = NULL;
 
 @implementation View
 
@@ -1002,8 +1143,8 @@ extern void print(const char* format, ...)
 Platform::Platform(Game* game)
 : _game(game)
 {
-    __gameGamePads = [[NSMutableDictionary alloc] init];
-    __gamePads = [[NSMutableDictionary alloc] init];
+    __activeGamepads = [[NSMutableDictionary alloc] init];
+    __gamepads = [[NSMutableArray alloc] init];
     __hidManagerRef = IOHIDManagerCreate(CFAllocatorGetDefault(), kIOHIDOptionsTypeNone);
     IOHIDManagerRegisterDeviceMatchingCallback(__hidManagerRef, hidDeviceDiscoveredCallback, NULL);
     IOHIDManagerRegisterDeviceRemovalCallback(__hidManagerRef, hidDeviceRemovalCallback, NULL);
@@ -1025,12 +1166,13 @@ Platform::~Platform()
     
     CFRelease(__hidManagerRef);
     __hidManagerRef = NULL;
-    [__gamePads release];
-    __gamePads = NULL;
-    [__gameGamePads release];
-    __gameGamePads = NULL;
+    [__activeGamepads release];
+    __activeGamepads = NULL;
+    [__gamepads release];
+    __gamepads = NULL;
 }
 
+    
 Platform* Platform::create(Game* game, void* attachToWindow)
 {
     __attachToWindow = attachToWindow;
@@ -1328,42 +1470,52 @@ unsigned int Platform::getGamepadsConnected()
 {
     Game* game = Game::getInstance();
     
-    // Locate any newly connected devices
-    if(game->isInitialized()) {
-        for(NSNumber *key in __gamePads) {
-            OSXGamepad *gamepad = [__gamePads objectForKey:key];
-            if([__gameGamePads objectForKey:key] == NULL) {
-                unsigned int handle = game->createGamepad([[gamepad identifierName] cStringUsingEncoding:NSASCIIStringEncoding], [key unsignedIntValue], [gamepad numberOfButtons], [gamepad numberOfAxis], [gamepad numberOfTriggers]);
+    if(game->isInitialized())
+    {
+        // Locate any newly connected devices
+        for(OSXGamepad *gamepad in __gamepads)
+        {
+            NSNumber *locationID = [gamepad locationID];
+            if([__activeGamepads objectForKey:locationID] == NULL)
+            {
+                unsigned int handle = game->createGamepad([[gamepad identifierName] cStringUsingEncoding:NSASCIIStringEncoding],
+                                                          [locationID unsignedIntValue],
+                                                          [gamepad numberOfButtons],
+                                                          [gamepad numberOfSticks],
+                                                          [gamepad numberOfTriggers]);
                 NSNumber *handleObj = [NSNumber numberWithUnsignedInt:handle];
-                [__gameGamePads setObject:handleObj forKey:key];
-            
+                [__activeGamepads setObject:handleObj forKey:locationID];
                 game->gamepadEvent(Gamepad::CONNECTED_EVENT, game->getGamepad(handle));
             }
+            
         }
         
         // Detect any disconnected gamepads
-        NSMutableArray *deadKeys = [NSMutableArray array];
-        for(NSNumber *key in __gameGamePads) {
-            if([__gamePads objectForKey:key] == NULL) {
-                game->gamepadEvent(Gamepad::DISCONNECTED_EVENT, game->getGamepad([key unsignedIntValue]));
-                [deadKeys addObject:key];
+        NSMutableArray *deadGamepads = [NSMutableArray array];
+        for(NSNumber *locationID in __activeGamepads)
+        {
+            OSXGamepad *gamepad = gamepadForLocationID(locationID);
+            if(gamepad == NULL)
+            {
+                NSNumber *gameHandle = [__activeGamepads objectForKey:locationID];
+                game->gamepadEvent(Gamepad::DISCONNECTED_EVENT, game->getGamepad([gameHandle unsignedIntValue]));
+                [deadGamepads addObject:locationID];
             }
         }
-        [__gameGamePads removeObjectsForKeys:deadKeys];
+        [__activeGamepads removeObjectsForKeys:deadGamepads];
     }
-    return [__gamePads count];
+    return [__gamepads count];
 }
 
 bool Platform::isGamepadConnected(unsigned int gamepadHandle)
 {
-    NSNumber *nID = [NSNumber numberWithInt:gamepadHandle];
-    return ([__gamePads objectForKey:nID] != NULL);
+    OSXGamepad *gamepad = gamepadForGameHandle(gamepadHandle);
+    return (gamepad != NULL);
 }
 
 const char* Platform::getGamepadId(unsigned int gamepadHandle)
 {
-    NSNumber *nID = [NSNumber numberWithInt:gamepadHandle];
-    OSXGamepad *gamepad = [__gamePads objectForKey:nID];
+    OSXGamepad *gamepad = gamepadForGameHandle(gamepadHandle);
     if(gamepad)
     {
         return [[gamepad productName] cStringUsingEncoding:NSASCIIStringEncoding];
@@ -1373,8 +1525,7 @@ const char* Platform::getGamepadId(unsigned int gamepadHandle)
 
 unsigned int Platform::getGamepadButtonCount(unsigned int gamepadHandle)
 {
-    NSNumber *nID = [NSNumber numberWithInt:gamepadHandle];
-    OSXGamepad *gamepad = [__gamePads objectForKey:nID];
+    OSXGamepad *gamepad = gamepadForGameHandle(gamepadHandle);
     if(gamepad)
     {
         return [gamepad numberOfButtons];
@@ -1384,22 +1535,21 @@ unsigned int Platform::getGamepadButtonCount(unsigned int gamepadHandle)
 
 bool Platform::getGamepadButtonState(unsigned int gamepadHandle, unsigned int buttonIndex)
 {
-    NSNumber *nID = [NSNumber numberWithInt:gamepadHandle];
-    OSXGamepad *gamepad = [__gamePads objectForKey:nID];
-    if(gamepad)
+    OSXGamepad *gamepad = gamepadForGameHandle(gamepadHandle);
+    OSXGamepadButton *button = [gamepad buttonAtIndex:buttonIndex];
+    if(button)
     {
-        return [gamepad stateOfButton:buttonIndex];
+        return [button state];
     }
     return false;
 }
 
 unsigned int Platform::getGamepadJoystickCount(unsigned int gamepadHandle)
 {
-    NSNumber *nID = [NSNumber numberWithInt:gamepadHandle];
-    OSXGamepad *gamepad = [__gamePads objectForKey:nID];
+    OSXGamepad *gamepad = gamepadForGameHandle(gamepadHandle);
     if(gamepad)
     {
-        return [gamepad numberOfAxis];
+        return [gamepad numberOfSticks];
     }
     return 0;
 }
@@ -1435,7 +1585,33 @@ float Platform::getGamepadTriggerValue(unsigned int gamepadHandle, unsigned int
 
 }
 
-
+OSXGamepad *gamepadForLocationID(NSNumber *locationID)
+{
+    OSXGamepad *fgamepad = NULL;
+    for(OSXGamepad *gamepad in __gamepads)
+    {
+        if([[gamepad locationID] isEqual:locationID])
+        {
+            fgamepad = gamepad;
+            break;
+        }
+    }
+    return fgamepad;
+}
+OSXGamepad *gamepadForGameHandle(int gameHandle)
+{
+    OSXGamepad *gamepad = NULL;
+    for(NSNumber *locationID in __activeGamepads)
+    {
+        NSNumber *handleID = [__activeGamepads objectForKey:locationID];
+        if([handleID integerValue] == gameHandle)
+        {
+            gamepad = gamepadForLocationID(locationID);
+            break;
+        }
+    }
+    return gamepad;
+}
 
 
 CFMutableDictionaryRef IOHIDCreateDeviceMatchingDictionary( UInt32 inUsagePage, UInt32 inUsage ) {
@@ -1486,49 +1662,42 @@ int IOHIDDeviceGetIntProperty(IOHIDDeviceRef deviceRef, CFStringRef key) {
 	CFNumberGetValue((CFNumberRef) typeRef, kCFNumberSInt32Type, &value);
 	return value;
 }
-void IOHIDAxisXYValue(CFIndex value, CFIndex range, int * outX, int * outY) {
-	if (value == range) {
-		*outX = 0;
-        *outY = 0;
-	} else {
-		if (value > 0 && value < range / 2) {
-			*outX = 1;
-		} else if (value > range / 2) {
-			*outX = -1;
-		} else {
-			*outX = 0;
-		}
-		
-		if (value > range / 4 * 3 || value < range / 4) {
-			*outY = -1;
-		} else if (value > range / 4 && value < range / 4 * 3) {
-			*outY = 1;
-		} else {
-			*outY = 0;
-		}
-	}
-}
+
 
 static void hidDeviceDiscoveredCallback(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef) {
-    OSXGamepad *gamepad = [[OSXGamepad alloc] initWithDevice:inIOHIDDeviceRef];
-    NSNumber *locID = (NSNumber*)IOHIDDeviceGetProperty(inIOHIDDeviceRef, CFSTR(kIOHIDLocationIDKey));
+    CFNumberRef locID = (CFNumberRef)IOHIDDeviceGetProperty(inIOHIDDeviceRef, CFSTR(kIOHIDLocationIDKey));
     if(locID)
     {
-        [__gamePads setObject:gamepad forKey:locID];
+        OSXGamepad *gamepad = [[OSXGamepad alloc] initWithDevice:inIOHIDDeviceRef];
+        [__gamepads addObject:gamepad];
     }
+    
 }
 static void hidDeviceRemovalCallback(void *inContext, IOReturn inResult, void *inSender, IOHIDDeviceRef inIOHIDDeviceRef) {
+    int removeIndex = -1;
     NSNumber *locID = (NSNumber*)IOHIDDeviceGetProperty(inIOHIDDeviceRef, CFSTR(kIOHIDLocationIDKey));
     if(locID)
     {
-        [__gamePads removeObjectForKey:locID];
+        for(int i = 0; i < [__gamepads count]; i++)
+        {
+            OSXGamepad *gamepad = [__gamepads objectAtIndex:i];
+            if([[gamepad locationID] isEqual:locID])
+            {
+                removeIndex = i;
+                break;
+            }
+        }
+    }
+    if(removeIndex >= 0)
+    {
+        [__gamepads removeObjectAtIndex:removeIndex];
     }
 }
 
-static void HidDeviceValueAvailableCallback(void *inContext, IOReturn inResult,  void *inSender) {
-    //printf( "(context: %p, result: %p, sender: %p ).\n", inContext, ( void * ) inResult, inSender );
+static void hidDeviceValueAvailableCallback(void *inContext, IOReturn inResult,  void *inSender) {
     OSXGamepad *d = (OSXGamepad*)inContext;
-    do {
+    do
+    {
         IOHIDValueRef valueRef = IOHIDQueueCopyNextValueWithTimeout( ( IOHIDQueueRef ) inSender, 0. );
         if (!valueRef) break;
         [d hidValueAvailable:valueRef];