|
@@ -7,14 +7,24 @@
|
|
|
#include "Form.h"
|
|
#include "Form.h"
|
|
|
#include "ScriptController.h"
|
|
#include "ScriptController.h"
|
|
|
#include <unistd.h>
|
|
#include <unistd.h>
|
|
|
|
|
+#include <IOKit/hid/IOHIDLib.h>
|
|
|
#import <Cocoa/Cocoa.h>
|
|
#import <Cocoa/Cocoa.h>
|
|
|
#import <QuartzCore/CVDisplayLink.h>
|
|
#import <QuartzCore/CVDisplayLink.h>
|
|
|
#import <OpenGL/OpenGL.h>
|
|
#import <OpenGL/OpenGL.h>
|
|
|
#import <mach/mach_time.h>
|
|
#import <mach/mach_time.h>
|
|
|
|
|
+#import <Foundation/Foundation.h>
|
|
|
|
|
+
|
|
|
|
|
+// These should probably be moved to a platform common file
|
|
|
|
|
+#define SONY_USB_VENDOR_ID 0x54c
|
|
|
|
|
+#define SONY_USB_PS3_PRODUCT_ID 0x268
|
|
|
|
|
+
|
|
|
|
|
|
|
|
using namespace std;
|
|
using namespace std;
|
|
|
using namespace gameplay;
|
|
using namespace gameplay;
|
|
|
|
|
|
|
|
|
|
+@class View;
|
|
|
|
|
+@class OSXGamepad;
|
|
|
|
|
+
|
|
|
// Default to 720p
|
|
// Default to 720p
|
|
|
static int __width = 1280;
|
|
static int __width = 1280;
|
|
|
static int __height = 720;
|
|
static int __height = 720;
|
|
@@ -40,6 +50,29 @@ static void* __attachToWindow = NULL;
|
|
|
static bool __mouseCaptured = false;
|
|
static bool __mouseCaptured = false;
|
|
|
static CGPoint __mouseCapturePoint;
|
|
static CGPoint __mouseCapturePoint;
|
|
|
static bool __cursorVisible = true;
|
|
static bool __cursorVisible = true;
|
|
|
|
|
+static View* __view = NULL;
|
|
|
|
|
+
|
|
|
|
|
+static NSMutableDictionary *__activeGamepads = NULL;
|
|
|
|
|
+static NSMutableArray *__gamepads = NULL;
|
|
|
|
|
+static IOHIDManagerRef __hidManagerRef = NULL;
|
|
|
|
|
+
|
|
|
|
|
+// Gamepad Helper Function
|
|
|
|
|
+OSXGamepad *gamepadForLocationID(NSNumber *locationID);
|
|
|
|
|
+OSXGamepad *gamepadForLocationIDValue(unsigned int locationIDValue);
|
|
|
|
|
+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);
|
|
|
|
|
+
|
|
|
|
|
+// 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);
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
|
|
|
double getMachTimeInMilliseconds()
|
|
double getMachTimeInMilliseconds()
|
|
|
{
|
|
{
|
|
@@ -54,7 +87,537 @@ double getMachTimeInMilliseconds()
|
|
|
return ((double)mach_absolute_time() * (double)s_timebase_info.numer) / (kOneMillion * (double)s_timebase_info.denom);
|
|
return ((double)mach_absolute_time() * (double)s_timebase_info.numer) / (kOneMillion * (double)s_timebase_info.denom);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-@class View;
|
|
|
|
|
|
|
+
|
|
|
|
|
+@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);
|
|
|
|
|
+ }
|
|
|
|
|
+ return self;
|
|
|
|
|
+}
|
|
|
|
|
+- (void)dealloc
|
|
|
|
|
+{
|
|
|
|
|
+ CFRelease(e);
|
|
|
|
|
+ [super dealloc];
|
|
|
|
|
+}
|
|
|
|
|
+- (IOHIDElementRef)element
|
|
|
|
|
+{
|
|
|
|
|
+ return e;
|
|
|
|
|
+}
|
|
|
|
|
+- (IOHIDElementCookie)cookie
|
|
|
|
|
+{
|
|
|
|
|
+ return IOHIDElementGetCookie(e);
|
|
|
|
|
+}
|
|
|
|
|
+- (bool)isHatSwitch {
|
|
|
|
|
+ return (IOHIDElementGetUsage(e) == kHIDUsage_GD_Hatswitch);
|
|
|
|
|
+}
|
|
|
|
|
+- (uint32_t)usage
|
|
|
|
|
+{
|
|
|
|
|
+ return IOHIDElementGetUsage(e);
|
|
|
|
|
+}
|
|
|
|
|
+- (uint32_t)usagePage
|
|
|
|
|
+{
|
|
|
|
|
+ return IOHIDElementGetUsagePage(e);
|
|
|
|
|
+}
|
|
|
|
|
+- (CFIndex)logicalMinimum
|
|
|
|
|
+{
|
|
|
|
|
+ return IOHIDElementGetLogicalMin(e);
|
|
|
|
|
+}
|
|
|
|
|
+- (CFIndex)logicalMaximum
|
|
|
|
|
+{
|
|
|
|
|
+ return IOHIDElementGetLogicalMax(e);
|
|
|
|
|
+}
|
|
|
|
|
+- (float)calibratedValue
|
|
|
|
|
+{
|
|
|
|
|
+ float cmax = 2.0f;
|
|
|
|
|
+ float cmin = 0.0f;
|
|
|
|
|
+ return ((((v - [self logicalMinimum]) * (cmax - cmin)) / ([self logicalMaximum] - [self logicalMinimum])) + cmin - 1.0f);
|
|
|
|
|
+}
|
|
|
|
|
+- (CFIndex)value
|
|
|
|
|
+{
|
|
|
|
|
+ return v;
|
|
|
|
|
+}
|
|
|
|
|
+- (void)setValue:(CFIndex)value
|
|
|
|
|
+{
|
|
|
|
|
+ v = value;
|
|
|
|
|
+}
|
|
|
|
|
+@end
|
|
|
|
|
+
|
|
|
|
|
+@interface OSXGamepadButton : NSObject
|
|
|
|
|
+{
|
|
|
|
|
+ IOHIDElementRef e;
|
|
|
|
|
+ IOHIDElementRef te;
|
|
|
|
|
+ bool state;
|
|
|
|
|
+ int triggerValue;
|
|
|
|
|
+}
|
|
|
|
|
++ gamepadButtonWithButtonElement:(IOHIDElementRef)element;
|
|
|
|
|
+- initWithButtonElement:(IOHIDElementRef)element;
|
|
|
|
|
+- (void)setTriggerElement:(IOHIDElementRef)element;
|
|
|
|
|
+- (IOHIDElementRef)element;
|
|
|
|
|
+- (IOHIDElementCookie)cookie;
|
|
|
|
|
+- (IOHIDElementRef)triggerElement;
|
|
|
|
|
+- (IOHIDElementCookie)triggerCookie;
|
|
|
|
|
+
|
|
|
|
|
+- (bool)isTriggerButton;
|
|
|
|
|
+- (uint32_t)usage;
|
|
|
|
|
+- (uint32_t)usagePage;
|
|
|
|
|
+- (int)stateValue;
|
|
|
|
|
+- (float)calibratedStateValue;
|
|
|
|
|
+- (void)setStateValue:(int)value;
|
|
|
|
|
+- (bool)state;
|
|
|
|
|
+- (void)setState:(bool)state;
|
|
|
|
|
+@end
|
|
|
|
|
+@implementation OSXGamepadButton
|
|
|
|
|
++ gamepadButtonWithButtonElement:(IOHIDElementRef)element
|
|
|
|
|
+{
|
|
|
|
|
+ return [[[[self class] alloc] initWithButtonElement:element] autorelease];
|
|
|
|
|
+}
|
|
|
|
|
+- initWithButtonElement:(IOHIDElementRef)element
|
|
|
|
|
+{
|
|
|
|
|
+ if((self = [super init]))
|
|
|
|
|
+ {
|
|
|
|
|
+ e = (IOHIDElementRef)CFRetain(element);
|
|
|
|
|
+ te = NULL;
|
|
|
|
|
+ state = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ return self;
|
|
|
|
|
+}
|
|
|
|
|
+- (void)dealloc
|
|
|
|
|
+{
|
|
|
|
|
+ CFRelease(e);
|
|
|
|
|
+ if(te != NULL) CFRelease(te);
|
|
|
|
|
+ [super dealloc];
|
|
|
|
|
+}
|
|
|
|
|
+- (void)setTriggerElement:(IOHIDElementRef)element {
|
|
|
|
|
+ if(te)
|
|
|
|
|
+ {
|
|
|
|
|
+ CFRelease(te);
|
|
|
|
|
+ te = NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+ if(element)
|
|
|
|
|
+ {
|
|
|
|
|
+ te = (IOHIDElementRef)CFRetain(element);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+- (IOHIDElementRef)element
|
|
|
|
|
+{
|
|
|
|
|
+ return e;
|
|
|
|
|
+}
|
|
|
|
|
+- (IOHIDElementCookie)cookie
|
|
|
|
|
+{
|
|
|
|
|
+ return IOHIDElementGetCookie(e);
|
|
|
|
|
+}
|
|
|
|
|
+- (IOHIDElementRef)triggerElement
|
|
|
|
|
+{
|
|
|
|
|
+ return te;
|
|
|
|
|
+}
|
|
|
|
|
+- (IOHIDElementCookie)triggerCookie
|
|
|
|
|
+{
|
|
|
|
|
+ return IOHIDElementGetCookie(te);
|
|
|
|
|
+}
|
|
|
|
|
+- (bool)isTriggerButton
|
|
|
|
|
+{
|
|
|
|
|
+ return (te != NULL);
|
|
|
|
|
+}
|
|
|
|
|
+- (uint32_t)usage
|
|
|
|
|
+{
|
|
|
|
|
+ return IOHIDElementGetUsage(e);
|
|
|
|
|
+}
|
|
|
|
|
+- (uint32_t)usagePage
|
|
|
|
|
+{
|
|
|
|
|
+ return IOHIDElementGetUsagePage(e);
|
|
|
|
|
+}
|
|
|
|
|
+- (void)setStateValue:(int)value {
|
|
|
|
|
+ triggerValue = value;
|
|
|
|
|
+}
|
|
|
|
|
+- (int)stateValue
|
|
|
|
|
+{
|
|
|
|
|
+ return triggerValue;
|
|
|
|
|
+}
|
|
|
|
|
+- (float)calibratedStateValue
|
|
|
|
|
+{
|
|
|
|
|
+ return (float)triggerValue; // TODO: Need to figure out expected range
|
|
|
|
|
+}
|
|
|
|
|
+- (bool)state
|
|
|
|
|
+{
|
|
|
|
|
+ return state;
|
|
|
|
|
+}
|
|
|
|
|
+- (void)setState:(bool)s
|
|
|
|
|
+{
|
|
|
|
|
+ state = s;
|
|
|
|
|
+}
|
|
|
|
|
+@end
|
|
|
|
|
+
|
|
|
|
|
+@interface OSXGamepad : NSObject
|
|
|
|
|
+{
|
|
|
|
|
+ IOHIDDeviceRef hidDeviceRef;
|
|
|
|
|
+ IOHIDQueueRef queueRef;
|
|
|
|
|
+ NSMutableArray *buttons;
|
|
|
|
|
+ NSMutableArray *triggerButtons;
|
|
|
|
|
+ NSMutableArray *axes;
|
|
|
|
|
+}
|
|
|
|
|
+@property (assign) IOHIDDeviceRef hidDeviceRef;
|
|
|
|
|
+@property (assign) IOHIDQueueRef queueRef;
|
|
|
|
|
+@property (retain) NSMutableArray *buttons;
|
|
|
|
|
+@property (retain) NSMutableArray *triggerButtons;
|
|
|
|
|
+@property (retain) NSMutableArray *axes;
|
|
|
|
|
+
|
|
|
|
|
+- initWithDevice:(IOHIDDeviceRef)rawDevice;
|
|
|
|
|
+- (IOHIDDeviceRef)rawDevice;
|
|
|
|
|
+- (NSNumber*)locationID;
|
|
|
|
|
+
|
|
|
|
|
+- (void)initializeGamepadElements;
|
|
|
|
|
+- (OSXGamepadButton*)buttonWithCookie:(IOHIDElementCookie)cookie;
|
|
|
|
|
+
|
|
|
|
|
+- (bool)startListening;
|
|
|
|
|
+- (void)stopListening;
|
|
|
|
|
+
|
|
|
|
|
+- (NSString *)identifierName;
|
|
|
|
|
+- (NSString *)productName;
|
|
|
|
|
+- (NSString *)manufacturerName;
|
|
|
|
|
+- (NSString *)serialNumber;
|
|
|
|
|
+- (int)vendorID;
|
|
|
|
|
+- (int)productID;
|
|
|
|
|
+
|
|
|
|
|
+- (NSUInteger)numberOfAxes;
|
|
|
|
|
+- (NSUInteger)numberOfSticks;
|
|
|
|
|
+- (NSUInteger)numberOfButtons;
|
|
|
|
|
+- (NSUInteger)numberOfTriggerButtons;
|
|
|
|
|
+- (OSXGamepadAxis*)axisAtIndex:(NSUInteger)index;
|
|
|
|
|
+- (OSXGamepadButton*)buttonAtIndex:(NSUInteger)index;
|
|
|
|
|
+- (OSXGamepadButton*)triggerButtonAtIndex:(NSUInteger)index;
|
|
|
|
|
+@end
|
|
|
|
|
+
|
|
|
|
|
+@implementation OSXGamepad
|
|
|
|
|
+
|
|
|
|
|
+@synthesize hidDeviceRef;
|
|
|
|
|
+@synthesize queueRef;
|
|
|
|
|
+@synthesize buttons;
|
|
|
|
|
+@synthesize triggerButtons;
|
|
|
|
|
+@synthesize axes;
|
|
|
|
|
+
|
|
|
|
|
+- initWithDevice:(IOHIDDeviceRef)rawDevice
|
|
|
|
|
+{
|
|
|
|
|
+ if((self = [super init]))
|
|
|
|
|
+ {
|
|
|
|
|
+ [self setButtons:[NSMutableArray array]];
|
|
|
|
|
+ [self setTriggerButtons:[NSMutableArray array]];
|
|
|
|
|
+ [self setAxes:[NSMutableArray array]];
|
|
|
|
|
+
|
|
|
|
|
+ CFRetain(rawDevice);
|
|
|
|
|
+ IOHIDQueueRef queue = IOHIDQueueCreate(CFAllocatorGetDefault(), rawDevice, 10, kIOHIDOptionsTypeNone);
|
|
|
|
|
+ [self setHidDeviceRef:rawDevice];
|
|
|
|
|
+ [self setQueueRef:queue];
|
|
|
|
|
+
|
|
|
|
|
+ [self initializeGamepadElements];
|
|
|
|
|
+ [self startListening];
|
|
|
|
|
+ }
|
|
|
|
|
+ return self;
|
|
|
|
|
+}
|
|
|
|
|
+- (void)dealloc
|
|
|
|
|
+{
|
|
|
|
|
+ [self stopListening];
|
|
|
|
|
+
|
|
|
|
|
+ CFRelease([self rawDevice]);
|
|
|
|
|
+ CFRelease([self queueRef]);
|
|
|
|
|
+ [self setQueueRef:NULL];
|
|
|
|
|
+ [self setHidDeviceRef:NULL];
|
|
|
|
|
+
|
|
|
|
|
+ [self setButtons:NULL];
|
|
|
|
|
+ [self setTriggerButtons:NULL];
|
|
|
|
|
+ [self setAxes:NULL];
|
|
|
|
|
+ [super dealloc];
|
|
|
|
|
+}
|
|
|
|
|
+- (IOHIDDeviceRef)rawDevice
|
|
|
|
|
+{
|
|
|
|
|
+ return [self hidDeviceRef];
|
|
|
|
|
+}
|
|
|
|
|
+- (NSNumber*)locationID
|
|
|
|
|
+{
|
|
|
|
|
+ return (NSNumber*)IOHIDDeviceGetProperty([self rawDevice], CFSTR(kIOHIDLocationIDKey));
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+- (void)initializeGamepadElements
|
|
|
|
|
+{
|
|
|
|
|
+ CFArrayRef elements = IOHIDDeviceCopyMatchingElements([self rawDevice], NULL, kIOHIDOptionsTypeNone);
|
|
|
|
|
+ for(int i = 0; i < CFArrayGetCount(elements); i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ IOHIDElementRef hidElement = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i);
|
|
|
|
|
+ IOHIDElementType type = IOHIDElementGetType(hidElement);
|
|
|
|
|
+
|
|
|
|
|
+ if (type == kIOHIDElementTypeInput_Misc || type == kIOHIDElementTypeInput_Axis)
|
|
|
|
|
+ {
|
|
|
|
|
+ uint32_t pageUsage = IOHIDElementGetUsage(hidElement);
|
|
|
|
|
+ IOHIDElementCookie cookie = IOHIDElementGetCookie(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
|
|
|
|
|
+ // Note: Some of the pointers are for the 6-axis accelerometer in a PS3 controller
|
|
|
|
|
+ // Note: L2/R2 triggers are at cookie 39 and 40 base 10 tied to 9 and 10 button elements
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ if(type == kIOHIDElementTypeInput_Button)
|
|
|
|
|
+ {
|
|
|
|
|
+ OSXGamepadButton *button = [OSXGamepadButton gamepadButtonWithButtonElement:hidElement];
|
|
|
|
|
+ [[self buttons] addObject:button];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ // Go back and get proprietary information (e.g. triggers) and asscoaite with appropriate values
|
|
|
|
|
+ // Example for other trigger buttons
|
|
|
|
|
+ uint32_t vendorID = [self vendorID];
|
|
|
|
|
+ uint32_t productID = [self productID];
|
|
|
|
|
+ for(int i = 0; i < CFArrayGetCount(elements); i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ IOHIDElementRef hidElement = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i);
|
|
|
|
|
+ IOHIDElementType type = IOHIDElementGetType(hidElement);
|
|
|
|
|
+ IOHIDElementCookie cookie = IOHIDElementGetCookie(hidElement);
|
|
|
|
|
+
|
|
|
|
|
+ // Gamepad specific code
|
|
|
|
|
+ // Not sure if there is a better way to associate buttons and misc hid elements :/
|
|
|
|
|
+ if(vendorID == SONY_USB_VENDOR_ID && productID == SONY_USB_PS3_PRODUCT_ID)
|
|
|
|
|
+ {
|
|
|
|
|
+ if((unsigned long)cookie == 39)
|
|
|
|
|
+ {
|
|
|
|
|
+ OSXGamepadButton *leftTrigger = [self buttonWithCookie:(IOHIDElementCookie)9];
|
|
|
|
|
+ if(leftTrigger)
|
|
|
|
|
+ {
|
|
|
|
|
+ [leftTrigger setTriggerElement:hidElement];
|
|
|
|
|
+ [[self triggerButtons] addObject:leftTrigger];
|
|
|
|
|
+ //[[self buttons] removeObject:leftTrigger]; Defer to gamepad team on this line.. not sure how they intend to tackle
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if((unsigned long)cookie == 40)
|
|
|
|
|
+ {
|
|
|
|
|
+ OSXGamepadButton *rightTrigger = [self buttonWithCookie:(IOHIDElementCookie)10];
|
|
|
|
|
+ if(rightTrigger)
|
|
|
|
|
+ {
|
|
|
|
|
+ [rightTrigger setTriggerElement:hidElement];
|
|
|
|
|
+ [[self triggerButtons] addObject:rightTrigger];
|
|
|
|
|
+ //[[self buttons] removeObject:rightTrigger];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|
|
|
|
|
+- (OSXGamepadButton*)buttonWithCookie:(IOHIDElementCookie)cookie {
|
|
|
|
|
+ for(OSXGamepadButton *b in [self buttons]) {
|
|
|
|
|
+ if([b cookie] == cookie) return b;
|
|
|
|
|
+ }
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+- (bool)startListening
|
|
|
|
|
+{
|
|
|
|
|
+ IOReturn kr = IOHIDDeviceOpen([self hidDeviceRef], kIOHIDOptionsTypeNone);
|
|
|
|
|
+ if(kr != 0) {
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ IOHIDDeviceScheduleWithRunLoop([self hidDeviceRef], CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
|
|
|
|
+
|
|
|
|
|
+ IOHIDQueueStart([self queueRef]);
|
|
|
|
|
+ IOHIDQueueRegisterValueAvailableCallback([self queueRef], hidDeviceValueAvailableCallback, self);
|
|
|
|
|
+
|
|
|
|
|
+ CFArrayRef elements = (CFArrayRef)[self watchedElements];
|
|
|
|
|
+ for(int i = 0; i < CFArrayGetCount(elements); i++)
|
|
|
|
|
+ {
|
|
|
|
|
+ IOHIDElementRef hidElement = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i);
|
|
|
|
|
+ IOHIDQueueAddElement([self queueRef], hidElement);
|
|
|
|
|
+ }
|
|
|
|
|
+ IOHIDQueueScheduleWithRunLoop([self queueRef], CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
|
|
+}
|
|
|
|
|
+- (void)stopListening
|
|
|
|
|
+{
|
|
|
|
|
+ IOHIDQueueUnscheduleFromRunLoop([self queueRef], CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
|
|
|
|
+ IOHIDQueueStop([self queueRef]);
|
|
|
|
|
+
|
|
|
|
|
+ IOHIDDeviceUnscheduleFromRunLoop([self hidDeviceRef], CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
|
|
|
|
+ IOHIDDeviceClose([self hidDeviceRef], kIOHIDOptionsTypeNone);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+- (NSString *)identifierName
|
|
|
|
|
+{
|
|
|
|
|
+ NSString *idName = NULL;
|
|
|
|
|
+ if(idName == NULL) idName = [self productName];
|
|
|
|
|
+ if(idName == NULL) idName = [self manufacturerName];
|
|
|
|
|
+ if(idName == NULL) idName = [self serialNumber];
|
|
|
|
|
+ if(idName == NULL) idName = [NSString stringWithFormat:@"%d-%d", [self vendorID], [self productID]];
|
|
|
|
|
+ return idName;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+- (NSString *)productName {
|
|
|
|
|
+ CFStringRef productName = (CFStringRef)IOHIDDeviceGetProperty([self rawDevice], CFSTR(kIOHIDProductKey));
|
|
|
|
|
+ if(productName == NULL || CFGetTypeID(productName) != CFStringGetTypeID()) {
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+ return (NSString*)productName;
|
|
|
|
|
+}
|
|
|
|
|
+- (NSString *)manufacturerName {
|
|
|
|
|
+ CFStringRef manufacturerName = (CFStringRef)IOHIDDeviceGetProperty([self rawDevice], CFSTR(kIOHIDManufacturerKey));
|
|
|
|
|
+ if(manufacturerName == NULL || CFGetTypeID(manufacturerName) != CFStringGetTypeID()) {
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+ return (NSString*)manufacturerName;
|
|
|
|
|
+}
|
|
|
|
|
+- (NSString *)serialNumber {
|
|
|
|
|
+ CFStringRef serialNumber = (CFStringRef)IOHIDDeviceGetProperty([self rawDevice], CFSTR(kIOHIDSerialNumberKey));
|
|
|
|
|
+ if(serialNumber == NULL || CFGetTypeID(serialNumber) != CFStringGetTypeID()) {
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+ return (NSString*)serialNumber;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+- (int)vendorID
|
|
|
|
|
+{
|
|
|
|
|
+ return IOHIDDeviceGetIntProperty([self rawDevice], CFSTR(kIOHIDVendorIDKey));
|
|
|
|
|
+}
|
|
|
|
|
+- (int)productID
|
|
|
|
|
+{
|
|
|
|
|
+ return IOHIDDeviceGetIntProperty([self rawDevice], CFSTR(kIOHIDProductIDKey));
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+- (NSUInteger)numberOfAxes
|
|
|
|
|
+{
|
|
|
|
|
+ return [[self axes] count];
|
|
|
|
|
+}
|
|
|
|
|
+- (NSUInteger)numberOfSticks
|
|
|
|
|
+{
|
|
|
|
|
+ return ([[self axes] count] / 2);
|
|
|
|
|
+}
|
|
|
|
|
+- (NSUInteger)numberOfButtons
|
|
|
|
|
+{
|
|
|
|
|
+ return [[self buttons] count];
|
|
|
|
|
+}
|
|
|
|
|
+- (NSUInteger)numberOfTriggerButtons
|
|
|
|
|
+{
|
|
|
|
|
+ return [[self triggerButtons] count];
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+- (OSXGamepadButton*)triggerButtonAtIndex:(NSUInteger)index
|
|
|
|
|
+{
|
|
|
|
|
+ OSXGamepadButton *b = NULL;
|
|
|
|
|
+ if(index < [[self triggerButtons] count])
|
|
|
|
|
+ {
|
|
|
|
|
+ b = [[self triggerButtons] objectAtIndex:index];
|
|
|
|
|
+ }
|
|
|
|
|
+ return b;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+- (OSXGamepadAxis*)axisAtIndex:(NSUInteger)index
|
|
|
|
|
+{
|
|
|
|
|
+ OSXGamepadAxis *a = NULL;
|
|
|
|
|
+ if(index < [[self axes] count])
|
|
|
|
|
+ {
|
|
|
|
|
+ a = [[self axes] objectAtIndex:index];
|
|
|
|
|
+ }
|
|
|
|
|
+ return a;
|
|
|
|
|
+}
|
|
|
|
|
+- (OSXGamepadButton*)buttonAtIndex:(NSUInteger)index
|
|
|
|
|
+{
|
|
|
|
|
+ OSXGamepadButton *b = NULL;
|
|
|
|
|
+ if(index < [[self buttons] count])
|
|
|
|
|
+ {
|
|
|
|
|
+ b = [[self buttons] objectAtIndex:index];
|
|
|
|
|
+ }
|
|
|
|
|
+ return b;
|
|
|
|
|
+}
|
|
|
|
|
+- (NSArray*)watchedElements
|
|
|
|
|
+{
|
|
|
|
|
+ NSMutableArray *r = [NSMutableArray array];
|
|
|
|
|
+ for(OSXGamepadButton *b in [self buttons])
|
|
|
|
|
+ {
|
|
|
|
|
+ [r addObject:(id)[b element]];
|
|
|
|
|
+ }
|
|
|
|
|
+ for(OSXGamepadAxis *a in [self axes])
|
|
|
|
|
+ {
|
|
|
|
|
+ [r addObject:(id)[a element]];
|
|
|
|
|
+ }
|
|
|
|
|
+ return [NSArray arrayWithArray:r];
|
|
|
|
|
+}
|
|
|
|
|
+- (void)hidValueAvailable:(IOHIDValueRef)value
|
|
|
|
|
+{
|
|
|
|
|
+ IOHIDElementRef element = IOHIDValueGetElement(value);
|
|
|
|
|
+ IOHIDElementCookie cookie = IOHIDElementGetCookie(element);
|
|
|
|
|
+
|
|
|
|
|
+ if(IOHIDValueGetLength(value) > 4) return; // saftey precaution for PS3 cotroller
|
|
|
|
|
+ CFIndex integerValue = IOHIDValueGetIntegerValue(value);
|
|
|
|
|
+
|
|
|
|
|
+ for(OSXGamepadAxis *a in [self axes])
|
|
|
|
|
+ {
|
|
|
|
|
+ if([a cookie] == cookie)
|
|
|
|
|
+ {
|
|
|
|
|
+ [a setValue:integerValue];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for(OSXGamepadButton *b in [self buttons])
|
|
|
|
|
+ {
|
|
|
|
|
+ if([b cookie] == cookie)
|
|
|
|
|
+ {
|
|
|
|
|
+ [b setState:(bool)integerValue];
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for(OSXGamepadButton *b in [self triggerButtons])
|
|
|
|
|
+ {
|
|
|
|
|
+ if([b triggerCookie] == cookie)
|
|
|
|
|
+ {
|
|
|
|
|
+ [b setStateValue:integerValue];
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+@end
|
|
|
|
|
+
|
|
|
|
|
|
|
|
@interface View : NSOpenGLView <NSWindowDelegate>
|
|
@interface View : NSOpenGLView <NSWindowDelegate>
|
|
|
{
|
|
{
|
|
@@ -66,10 +629,8 @@ double getMachTimeInMilliseconds()
|
|
|
Game* _game;
|
|
Game* _game;
|
|
|
unsigned int _gestureEvents;
|
|
unsigned int _gestureEvents;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
@end
|
|
@end
|
|
|
|
|
|
|
|
-static View* __view = NULL;
|
|
|
|
|
|
|
|
|
|
@implementation View
|
|
@implementation View
|
|
|
|
|
|
|
@@ -486,8 +1047,8 @@ int getKey(unsigned short keyCode, unsigned int modifierFlags)
|
|
|
return Keyboard::KEY_F10;
|
|
return Keyboard::KEY_F10;
|
|
|
|
|
|
|
|
// MACOS reserved:
|
|
// MACOS reserved:
|
|
|
- //return Keyboard::KEY_F11;
|
|
|
|
|
- //return Keyboard::KEY_F12;
|
|
|
|
|
|
|
+ // return Keyboard::KEY_F11;
|
|
|
|
|
+ // return Keyboard::KEY_F12;
|
|
|
// return Keyboard::KEY_PAUSE;
|
|
// return Keyboard::KEY_PAUSE;
|
|
|
// return Keyboard::KEY_SCROLL_LOCK;
|
|
// return Keyboard::KEY_SCROLL_LOCK;
|
|
|
|
|
|
|
@@ -680,25 +1241,6 @@ int getKey(unsigned short keyCode, unsigned int modifierFlags)
|
|
|
[gameLock unlock];
|
|
[gameLock unlock];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-- (void)swipeWithEvent:(NSEvent *)event
|
|
|
|
|
-{
|
|
|
|
|
- if([self isGestureRegistered:Gesture::GESTURE_SWIPE] == false) return;
|
|
|
|
|
- /**
|
|
|
|
|
- * Gesture callback on Gesture::SWIPE events.
|
|
|
|
|
- *
|
|
|
|
|
- * @param x The x-coordinate of the start of the swipe.
|
|
|
|
|
- * @param y The y-coordinate of the start of the swipe.
|
|
|
|
|
- * @param direction The direction of the swipe
|
|
|
|
|
- *
|
|
|
|
|
- * @see Gesture::SWIPE_DIRECTION_UP
|
|
|
|
|
- * @see Gesture::SWIPE_DIRECTION_DOWN
|
|
|
|
|
- * @see Gesture::SWIPE_DIRECTION_LEFT
|
|
|
|
|
- * @see Gesture::SWIPE_DIRECTION_RIGHT
|
|
|
|
|
- */
|
|
|
|
|
- //[gameLock lock];
|
|
|
|
|
- //virtual void gestureSwipeEvent(int x, int y, int direction);
|
|
|
|
|
- //[gameLock unlock];
|
|
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
@end
|
|
@end
|
|
|
|
|
|
|
@@ -730,12 +1272,36 @@ extern void print(const char* format, ...)
|
|
|
Platform::Platform(Game* game)
|
|
Platform::Platform(Game* game)
|
|
|
: _game(game)
|
|
: _game(game)
|
|
|
{
|
|
{
|
|
|
|
|
+ __activeGamepads = [[NSMutableDictionary alloc] init];
|
|
|
|
|
+ __gamepads = [[NSMutableArray alloc] init];
|
|
|
|
|
+ __hidManagerRef = IOHIDManagerCreate(CFAllocatorGetDefault(), kIOHIDOptionsTypeNone);
|
|
|
|
|
+ IOHIDManagerRegisterDeviceMatchingCallback(__hidManagerRef, hidDeviceDiscoveredCallback, NULL);
|
|
|
|
|
+ IOHIDManagerRegisterDeviceRemovalCallback(__hidManagerRef, hidDeviceRemovalCallback, NULL);
|
|
|
|
|
+
|
|
|
|
|
+ CFDictionaryRef matchingCFDictRef = IOHIDCreateDeviceMatchingDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Joystick);
|
|
|
|
|
+ if (matchingCFDictRef) IOHIDManagerSetDeviceMatching(__hidManagerRef, matchingCFDictRef);
|
|
|
|
|
+ CFRelease(matchingCFDictRef);
|
|
|
|
|
+
|
|
|
|
|
+ IOHIDManagerScheduleWithRunLoop(__hidManagerRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
|
|
|
|
+ IOReturn kr = IOHIDManagerOpen(__hidManagerRef, kIOHIDOptionsTypeNone);
|
|
|
|
|
+ assert(kr == 0);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+
|
|
|
Platform::~Platform()
|
|
Platform::~Platform()
|
|
|
{
|
|
{
|
|
|
|
|
+ IOHIDManagerUnscheduleFromRunLoop(__hidManagerRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
|
|
|
|
|
+ IOHIDManagerClose(__hidManagerRef, kIOHIDOptionsTypeNone);
|
|
|
|
|
+
|
|
|
|
|
+ CFRelease(__hidManagerRef);
|
|
|
|
|
+ __hidManagerRef = NULL;
|
|
|
|
|
+ [__activeGamepads release];
|
|
|
|
|
+ __activeGamepads = NULL;
|
|
|
|
|
+ [__gamepads release];
|
|
|
|
|
+ __gamepads = NULL;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+
|
|
|
Platform* Platform::create(Game* game, void* attachToWindow)
|
|
Platform* Platform::create(Game* game, void* attachToWindow)
|
|
|
{
|
|
{
|
|
|
__attachToWindow = attachToWindow;
|
|
__attachToWindow = attachToWindow;
|
|
@@ -999,7 +1565,11 @@ bool Platform::mouseEventInternal(Mouse::MouseEvent evt, int x, int y, int wheel
|
|
|
|
|
|
|
|
bool Platform::isGestureSupported(Gesture::GestureEvent evt)
|
|
bool Platform::isGestureSupported(Gesture::GestureEvent evt)
|
|
|
{
|
|
{
|
|
|
- // TODO: Support Swipe and Tap
|
|
|
|
|
|
|
+ // Swipe unsupported as it is considered moving mouse cursor
|
|
|
|
|
+ // Two fingers is scrolling
|
|
|
|
|
+ // Three fingers is swipe, but is not always enabled on users system
|
|
|
|
|
+ // Tap not supported as it is considered a mouse click/button click
|
|
|
|
|
+ // on some systems making it difficult to differentiate
|
|
|
switch(evt)
|
|
switch(evt)
|
|
|
{
|
|
{
|
|
|
case Gesture::GESTURE_PINCH:
|
|
case Gesture::GESTURE_PINCH:
|
|
@@ -1012,12 +1582,12 @@ bool Platform::isGestureSupported(Gesture::GestureEvent evt)
|
|
|
|
|
|
|
|
void Platform::registerGesture(Gesture::GestureEvent evt)
|
|
void Platform::registerGesture(Gesture::GestureEvent evt)
|
|
|
{
|
|
{
|
|
|
- [__view registerGesture:evt];
|
|
|
|
|
|
|
+ [__view registerGesture:evt];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void Platform::unregisterGesture(Gesture::GestureEvent evt)
|
|
void Platform::unregisterGesture(Gesture::GestureEvent evt)
|
|
|
{
|
|
{
|
|
|
- [__view unregisterGesture:evt];
|
|
|
|
|
|
|
+ [__view unregisterGesture:evt];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool Platform::isGestureRegistered(Gesture::GestureEvent evt)
|
|
bool Platform::isGestureRegistered(Gesture::GestureEvent evt)
|
|
@@ -1027,63 +1597,283 @@ bool Platform::isGestureRegistered(Gesture::GestureEvent evt)
|
|
|
|
|
|
|
|
unsigned int Platform::getGamepadsConnected()
|
|
unsigned int Platform::getGamepadsConnected()
|
|
|
{
|
|
{
|
|
|
- return 0;
|
|
|
|
|
|
|
+ Game* game = Game::getInstance();
|
|
|
|
|
+
|
|
|
|
|
+ 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 numberOfTriggerButtons]);
|
|
|
|
|
+ NSNumber* handleObj = [NSNumber numberWithUnsignedInt:handle];
|
|
|
|
|
+ [__activeGamepads setObject:handleObj forKey:locationID];
|
|
|
|
|
+ game->gamepadEvent(Gamepad::CONNECTED_EVENT, game->getGamepad(handle));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Detect any disconnected gamepads
|
|
|
|
|
+ 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];
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ [__activeGamepads removeObjectsForKeys:deadGamepads];
|
|
|
|
|
+ }
|
|
|
|
|
+ return [__gamepads count];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool Platform::isGamepadConnected(unsigned int gamepadHandle)
|
|
bool Platform::isGamepadConnected(unsigned int gamepadHandle)
|
|
|
{
|
|
{
|
|
|
- return false;
|
|
|
|
|
|
|
+ OSXGamepad* gamepad = gamepadForLocationIDValue(gamepadHandle);
|
|
|
|
|
+ return (gamepad != NULL);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const char* Platform::getGamepadId(unsigned int gamepadHandle)
|
|
const char* Platform::getGamepadId(unsigned int gamepadHandle)
|
|
|
{
|
|
{
|
|
|
|
|
+ OSXGamepad* gamepad = gamepadForLocationIDValue(gamepadHandle);
|
|
|
|
|
+ if(gamepad)
|
|
|
|
|
+ {
|
|
|
|
|
+ return [[gamepad productName] cStringUsingEncoding:NSASCIIStringEncoding];
|
|
|
|
|
+ }
|
|
|
return NULL;
|
|
return NULL;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
unsigned int Platform::getGamepadButtonCount(unsigned int gamepadHandle)
|
|
unsigned int Platform::getGamepadButtonCount(unsigned int gamepadHandle)
|
|
|
{
|
|
{
|
|
|
|
|
+ OSXGamepad* gamepad = gamepadForLocationIDValue(gamepadHandle);
|
|
|
|
|
+ if(gamepad)
|
|
|
|
|
+ {
|
|
|
|
|
+ return [gamepad numberOfButtons];
|
|
|
|
|
+ }
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool Platform::getGamepadButtonState(unsigned int gamepadHandle, unsigned int buttonIndex)
|
|
bool Platform::getGamepadButtonState(unsigned int gamepadHandle, unsigned int buttonIndex)
|
|
|
{
|
|
{
|
|
|
|
|
+ OSXGamepad* gamepad = gamepadForLocationIDValue(gamepadHandle);
|
|
|
|
|
+ OSXGamepadButton* button = [gamepad buttonAtIndex:buttonIndex];
|
|
|
|
|
+ if(button)
|
|
|
|
|
+ {
|
|
|
|
|
+ return [button state];
|
|
|
|
|
+ }
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
unsigned int Platform::getGamepadJoystickCount(unsigned int gamepadHandle)
|
|
unsigned int Platform::getGamepadJoystickCount(unsigned int gamepadHandle)
|
|
|
{
|
|
{
|
|
|
|
|
+ OSXGamepad* gamepad = gamepadForLocationIDValue(gamepadHandle);
|
|
|
|
|
+ if(gamepad)
|
|
|
|
|
+ {
|
|
|
|
|
+ return [gamepad numberOfSticks];
|
|
|
|
|
+ }
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool Platform::isGamepadJoystickActive(unsigned int gamepadHandle, unsigned int joystickIndex)
|
|
bool Platform::isGamepadJoystickActive(unsigned int gamepadHandle, unsigned int joystickIndex)
|
|
|
{
|
|
{
|
|
|
- return false;
|
|
|
|
|
|
|
+ return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
float Platform::getGamepadJoystickAxisX(unsigned int gamepadHandle, unsigned int joystickIndex)
|
|
float Platform::getGamepadJoystickAxisX(unsigned int gamepadHandle, unsigned int joystickIndex)
|
|
|
{
|
|
{
|
|
|
- return 0.0f;
|
|
|
|
|
|
|
+ OSXGamepad* gamepad = gamepadForLocationIDValue(gamepadHandle);
|
|
|
|
|
+ OSXGamepadAxis* xAxis = [gamepad axisAtIndex:(joystickIndex*2)];
|
|
|
|
|
+ return [xAxis calibratedValue];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
float Platform::getGamepadJoystickAxisY(unsigned int gamepadHandle, unsigned int joystickIndex)
|
|
float Platform::getGamepadJoystickAxisY(unsigned int gamepadHandle, unsigned int joystickIndex)
|
|
|
{
|
|
{
|
|
|
- return 0.0f;
|
|
|
|
|
|
|
+ OSXGamepad* gamepad = gamepadForLocationIDValue(gamepadHandle);
|
|
|
|
|
+ OSXGamepadAxis* yAxis = [gamepad axisAtIndex:((joystickIndex*2)+1)];
|
|
|
|
|
+ return [yAxis calibratedValue];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void Platform::getGamepadJoystickAxisValues(unsigned int gamepadHandle, unsigned int joystickIndex, Vector2* outValue)
|
|
void Platform::getGamepadJoystickAxisValues(unsigned int gamepadHandle, unsigned int joystickIndex, Vector2* outValue)
|
|
|
{
|
|
{
|
|
|
|
|
+ OSXGamepad* gamepad = gamepadForLocationIDValue(gamepadHandle);
|
|
|
|
|
+ OSXGamepadAxis* xAxis = [gamepad axisAtIndex:(joystickIndex*2)];
|
|
|
|
|
+ OSXGamepadAxis* yAxis = [gamepad axisAtIndex:((joystickIndex*2)+1)];
|
|
|
|
|
+ if(outValue)
|
|
|
|
|
+ {
|
|
|
|
|
+ outValue->x = [xAxis calibratedValue];
|
|
|
|
|
+ outValue->y = [yAxis calibratedValue];
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
unsigned int Platform::getGamepadTriggerCount(unsigned int gamepadHandle)
|
|
unsigned int Platform::getGamepadTriggerCount(unsigned int gamepadHandle)
|
|
|
{
|
|
{
|
|
|
- return 0;
|
|
|
|
|
|
|
+ OSXGamepad *gamepad = gamepadForLocationIDValue(gamepadHandle);
|
|
|
|
|
+ return [gamepad numberOfTriggerButtons];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
float Platform::getGamepadTriggerValue(unsigned int gamepadHandle, unsigned int triggerIndex)
|
|
float Platform::getGamepadTriggerValue(unsigned int gamepadHandle, unsigned int triggerIndex)
|
|
|
{
|
|
{
|
|
|
|
|
+ OSXGamepad* gamepad = gamepadForLocationIDValue(gamepadHandle);
|
|
|
|
|
+ OSXGamepadButton* button = [gamepad triggerButtonAtIndex:triggerIndex];
|
|
|
|
|
+ if(button)
|
|
|
|
|
+ {
|
|
|
|
|
+ return [button stateValue];
|
|
|
|
|
+ }
|
|
|
return 0.0f;
|
|
return 0.0f;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
|
+OSXGamepad* gamepadForLocationID(NSNumber* locationID)
|
|
|
|
|
+{
|
|
|
|
|
+ OSXGamepad* fgamepad = NULL;
|
|
|
|
|
+ for(OSXGamepad* gamepad in __gamepads)
|
|
|
|
|
+ {
|
|
|
|
|
+ if([[gamepad locationID] isEqual:locationID])
|
|
|
|
|
+ {
|
|
|
|
|
+ fgamepad = gamepad;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ return fgamepad;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+OSXGamepad* gamepadForLocationIDValue(unsigned int locationIDValue)
|
|
|
|
|
+{
|
|
|
|
|
+ return gamepadForLocationID([NSNumber numberWithUnsignedInt:locationIDValue]);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+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)
|
|
|
|
|
+{
|
|
|
|
|
+ // create a dictionary to add usage page/usages to
|
|
|
|
|
+ CFMutableDictionaryRef result = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
|
|
|
|
+ if (result) {
|
|
|
|
|
+ if (inUsagePage)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Add key for device type to refine the matching dictionary.
|
|
|
|
|
+ CFNumberRef pageCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &inUsagePage);
|
|
|
|
|
+ if (pageCFNumberRef)
|
|
|
|
|
+ {
|
|
|
|
|
+ CFDictionarySetValue(result, CFSTR( kIOHIDDeviceUsagePageKey ), pageCFNumberRef);
|
|
|
|
|
+ CFRelease(pageCFNumberRef);
|
|
|
|
|
+
|
|
|
|
|
+ // note: the usage is only valid if the usage page is also defined
|
|
|
|
|
+ if (inUsage)
|
|
|
|
|
+ {
|
|
|
|
|
+ CFNumberRef usageCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &inUsage);
|
|
|
|
|
+ if (usageCFNumberRef)
|
|
|
|
|
+ {
|
|
|
|
|
+ CFDictionarySetValue(result, CFSTR(kIOHIDDeviceUsageKey), usageCFNumberRef);
|
|
|
|
|
+ CFRelease(usageCFNumberRef);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ fprintf(stderr, "%s: CFNumberCreate( usage ) failed.", __PRETTY_FUNCTION__);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ fprintf( stderr, "%s: CFNumberCreate( usage page ) failed.", __PRETTY_FUNCTION__);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ fprintf( stderr, "%s: CFDictionaryCreateMutable failed.", __PRETTY_FUNCTION__);
|
|
|
|
|
+ }
|
|
|
|
|
+ return result;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+CFStringRef IOHIDDeviceGetStringProperty(IOHIDDeviceRef deviceRef, CFStringRef key)
|
|
|
|
|
+{
|
|
|
|
|
+ CFTypeRef typeRef = IOHIDDeviceGetProperty(deviceRef, key);
|
|
|
|
|
+ if (typeRef == NULL || CFGetTypeID(typeRef) != CFNumberGetTypeID())
|
|
|
|
|
+ {
|
|
|
|
|
+ return NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+ return (CFStringRef)typeRef;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+int IOHIDDeviceGetIntProperty(IOHIDDeviceRef deviceRef, CFStringRef key)
|
|
|
|
|
+{
|
|
|
|
|
+ CFTypeRef typeRef = IOHIDDeviceGetProperty(deviceRef, key);
|
|
|
|
|
+ if (typeRef == NULL || CFGetTypeID(typeRef) != CFNumberGetTypeID())
|
|
|
|
|
+ {
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ int value;
|
|
|
|
|
+ CFNumberGetValue((CFNumberRef) typeRef, kCFNumberSInt32Type, &value);
|
|
|
|
|
+ return value;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void hidDeviceDiscoveredCallback(void* inContext, IOReturn inResult, void* inSender, IOHIDDeviceRef inIOHIDDeviceRef)
|
|
|
|
|
+{
|
|
|
|
|
+ CFNumberRef locID = (CFNumberRef)IOHIDDeviceGetProperty(inIOHIDDeviceRef, CFSTR(kIOHIDLocationIDKey));
|
|
|
|
|
+ if(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)
|
|
|
|
|
+ {
|
|
|
|
|
+ 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)
|
|
|
|
|
+{
|
|
|
|
|
+ OSXGamepad* d = (OSXGamepad*)inContext;
|
|
|
|
|
+ do
|
|
|
|
|
+ {
|
|
|
|
|
+ IOHIDValueRef valueRef = IOHIDQueueCopyNextValueWithTimeout( ( IOHIDQueueRef ) inSender, 0. );
|
|
|
|
|
+ if (!valueRef) break;
|
|
|
|
|
+ [d hidValueAvailable:valueRef];
|
|
|
|
|
+ CFRelease(valueRef); // Don't forget to release our HID value reference
|
|
|
|
|
+ } while (1);
|
|
|
|
|
+}
|
|
|
#endif
|
|
#endif
|