Skip to content
Browse files

first commit

  • Loading branch information...
0 parents commit ecd3187d88f49b9298316b6edbf96bee16a195b3 @DaToBSn committed Aug 26, 2010
80 PS3SixAxis/PS3SixAxis.h
@@ -0,0 +1,80 @@
+//
+// PS3SixAxis.h
+// PS3SixAxis
+//
+// Created by Tobias Wetzel on 04.05.10.
+// Copyright 2010 Outcut. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+
+
+@protocol PS3SixAxisDelegate <NSObject>
+@optional
+
+- (void) onDeviceConnected;
+- (void) onDeviceDisconnected;
+- (void) onDeviceConnectionError:(NSInteger)error;
+
+- (void) onAxisX:(NSInteger)x Y:(NSInteger)y Z:(NSInteger)z;
+
+- (void) onLeftStick:(NSPoint)axis pressed:(BOOL)isPressed;
+- (void) onRightStick:(NSPoint)axis pressed:(BOOL)isPressed;
+
+- (void) onNorthButton:(BOOL)state;
+- (void) onEastButton:(BOOL)state;
+- (void) onSouthButton:(BOOL)state;
+- (void) onWestButton:(BOOL)state;
+
+- (void) onNorthButtonWithPressure:(NSInteger)value;
+- (void) onEastButtonWithPressure:(NSInteger)value;
+- (void) onSouthButtonWithPressure:(NSInteger)value;
+- (void) onWestButtonWithPressure:(NSInteger)value;
+
+- (void) onTriangleButton:(BOOL)state;
+- (void) onCircleButton:(BOOL)state;
+- (void) onCrossButton:(BOOL)state;
+- (void) onSquareButton:(BOOL)state;
+
+- (void) onTriangleButtonWithPressure:(NSInteger)value;
+- (void) onCircleButtonWithPressure:(NSInteger)value;
+- (void) onCrossButtonWithPressure:(NSInteger)value;
+- (void) onSquareButtonWithPressure:(NSInteger)value;
+
+- (void) onL1Button:(BOOL)state;
+- (void) onL2Button:(BOOL)state;
+- (void) onR1Button:(BOOL)state;
+- (void) onR2Button:(BOOL)state;
+
+- (void) onL1ButtonWithPressure:(NSInteger)value;
+- (void) onL2ButtonWithPressure:(NSInteger)value;
+- (void) onR1ButtonWithPressure:(NSInteger)value;
+- (void) onR2ButtonWithPressure:(NSInteger)value;
+
+- (void) onSelectButton:(BOOL)state;
+- (void) onStartButton:(BOOL)state;
+- (void) onPSButton:(BOOL)state;
+
+@end
+
+
+@interface PS3SixAxis : NSObject {
+@private
+ id<PS3SixAxisDelegate> delegate;
+ BOOL useBuffered;
+}
+
++ (id) sixAixisController;
++ (id) sixAixisControllerWithDelegate:(id<PS3SixAxisDelegate>)aDelegate;
+- (id) initSixAixisControllerWithDelegate:(id<PS3SixAxisDelegate>)aDelegate;
+
+- (void)connect:(BOOL)enableBluetooth;
+- (void)disconnect;
+
+- (void)setDelegate:(id<PS3SixAxisDelegate>)aDelegate;
+- (id<PS3SixAxisDelegate>)delegate;
+
+- (void)setUseBuffered:(BOOL)doUseBuffered;
+- (BOOL)useBuffered;
+
+@end
1,243 PS3SixAxis/PS3SixAxis.m
@@ -0,0 +1,1243 @@
+//
+// PS3SixAxis.m
+// PS3_SixAxis
+//
+// Created by Tobias Wetzel on 04.05.10.
+// Copyright 2010 Outcut. All rights reserved.
+//
+
+#import "PS3SixAxis.h"
+#import <IOKit/hid/IOHIDLib.h>
+#import <Cocoa/Cocoa.h>
+#import <IOBluetooth/objc/IOBluetoothHostController.h>
+
+//#import "sixaxis.h"
+
+#pragma mark -
+#pragma mark conditional macro's
+
+#define DO_BLUETOOTH 1
+#define DO_SET_MASTER (DO_BLUETOOTH && 1)
+
+//#define TRACE 1
+
+#pragma mark -
+#pragma mark static globals
+
+enum Button {
+ kButtonsRelease = 0,
+ kTriangleButton = 16,
+ kCircleButton = 32,
+ kTriangleAndCircleButton = 48,
+ kCrossButton = 64,
+ kTriangleAndCrossButton = 80,
+ kCircleAndCrossButton = 96,
+ kTriangleAndCircleAndCrossButton = 112,
+ kSquareButton = 128,
+ kTriangleAndSquareButton = 144,
+ kCircleAndSquareButton = 160,
+ kTriangleAndSquareAndCircleButton = 176,
+ kCrossAndSquareButton = 192,
+ kCrossAndSquareAndTriangleButton = 208,
+ kCircleAndCrossAndSquareButton = 224,
+ kCircleAndCrossAndSquareAndTriangleButton = 240,
+
+
+ kL2 = 1,
+ kR2 = 2,
+ kL2R2 = 3,
+ kL1 = 4,
+ kL1L2 = 5,
+ kL1R2 = 6,
+ kL1L2R2 = 7,
+ kR1 = 8,
+ kR1L2 = 9,
+ kR1R2 = 10,
+ kR1R2L2 = 11,
+ kL1R1 = 12,
+ kL1L2R1 = 13,
+ kL1R1R2 = 14,
+ kL1L2R1R2 = 15
+} ButtonTags;
+
+enum DirectionButton {
+ kSelectButton = 1,
+ kStartButton = 8,
+ kSelectAndStartButton = 9,
+ kDirectionButtonsRelease = 0,
+ kLeftStickButton = 2,
+ kRightStickButton = 4,
+ kLeftAndRightStickButton = 6,
+ kNorthButton = 16,
+ kEastButton = 32,
+ kNorthEastButton = 48,
+ kSouthButton = 64,
+ kEastSouthButton = 96,
+ kWestButton = 128,
+ kWestNorthButton = 144,
+ kWestSouthButton = 192
+} DirectionButtonTags;
+
+#pragma mark -
+#pragma mark static functions
+
+@interface PS3SixAxis (Private)
+BOOL isConnected;
+BOOL doBluetooth;
+IOHIDManagerRef hidManagerRef;
+IOHIDDeviceRef gIOHIDDeviceRef = NULL;
+
+BluetoothDeviceAddress gMasterBluetoothAddress;
+Boolean gMasterBluetoothAddressValid = FALSE;
+
+BOOL isUseBuffered = YES;
+
+BOOL isLeftStickDown, preIsLeftStickDown;
+BOOL isRightStickDown, preIsRightStickDown;
+BOOL isTriangleButtonDown, preIsTriangleButtonDown;
+BOOL isCircleButtonDown, preIsCircleButtonDown;
+BOOL isCrossButtonDown, preIsCrossButtonDown;
+BOOL isSquareButtonDown, preIsSquareButtonDown;
+BOOL isL1ButtonDown, preIsL1ButtonDown;
+BOOL isL2ButtonDown, preIsL2ButtonDown;
+BOOL isR1ButtonDown, preIsR1ButtonDown;
+BOOL isR2ButtonDown, preIsR2ButtonDown;
+
+BOOL isNorthButtonDown, preIsNorthButtonDown;
+BOOL isEastButtonDown, preIsEastButtonDown;
+BOOL isSouthButtonDown, preIsSouthButtonDown;
+BOOL isWestButtonDown, preIsWestButtonDown;
+
+BOOL isSelectButtonDown, preIsSelectButtonDown;
+BOOL isStartButtonDown, preIsStartButtonDown;
+BOOL isPSButtonDown, preIsPSButtonDown;
+
+int preLeftStickX, preLeftStickY;
+int preRightStickX, preRightStickY;
+
+unsigned int mx, my, mz;
+
+PS3SixAxis *target = NULL;
+
+- (void) parse:(uint8_t*)data l:(CFIndex)length;
+- (void) parseUnBuffered:(uint8_t*)data l:(CFIndex)length;
+- (void) sendDeviceConnected;
+- (void) sendDeviceDisconnected;
+- (void) sendDeviceConnectionError:(NSInteger)error;
+@end
+
+@implementation PS3SixAxis (Private)
+
+// ask a IOHIDDevice for a feature report
+static IOReturn Get_DeviceFeatureReport(IOHIDDeviceRef inIOHIDDeviceRef, CFIndex inReportID, void* inReportBuffer, CFIndex* ioReportSize) {
+ IOReturn result = paramErr;
+ if (inIOHIDDeviceRef && ioReportSize && inReportBuffer) {
+ result = IOHIDDeviceGetReport(inIOHIDDeviceRef, kIOHIDReportTypeFeature, inReportID, inReportBuffer, ioReportSize);
+ if (noErr != result) {
+ printf("%s, IOHIDDeviceGetReport error: %ld (0x%08lX ).\n", __PRETTY_FUNCTION__, (long int) result, (long int) result);
+ }
+ }
+ return result;
+}
+
+// send a IOHIDDevice a feature report
+static IOReturn Set_DeviceFeatureReport(IOHIDDeviceRef inIOHIDDeviceRef, CFIndex inReportID, void* inReportBuffer, CFIndex inReportSize) {
+ IOReturn result = paramErr;
+ if (inIOHIDDeviceRef && inReportSize && inReportBuffer) {
+ result = IOHIDDeviceSetReport(inIOHIDDeviceRef, kIOHIDReportTypeFeature, inReportID, inReportBuffer, inReportSize);
+ if (noErr != result) {
+ printf("%s, IOHIDDeviceSetReport error: %ld (0x%08lX ).\n", __PRETTY_FUNCTION__, (long int) result, (long int) result);
+ }
+ }
+ return result;
+}
+
+// ask a PS3 IOHIDDevice for the bluetooth address of its master
+static IOReturn PS3_GetMasterBluetoothAddress(IOHIDDeviceRef inIOHIDDeviceRef, BluetoothDeviceAddress*ioBluetoothDeviceAddress) {
+ IOReturn result = noErr;
+ CFIndex reportID = 0xF5;
+ uint8_t report[8];
+ CFIndex reportSize = sizeof(report);
+ result = IOHIDDeviceGetReport(inIOHIDDeviceRef, kIOHIDReportTypeFeature, reportID, report, &reportSize);
+ if (noErr == result) {
+ if (ioBluetoothDeviceAddress) {
+ memcpy(ioBluetoothDeviceAddress, &report[2], sizeof(*ioBluetoothDeviceAddress));
+ }
+ } else{
+ printf("%s, IOHIDDeviceGetReport error: %ld (0x%08lX ).\n", __PRETTY_FUNCTION__, (long int) result, (long int) result);
+ }
+ return result;
+}
+
+// tell a PS3 IOHIDDevice what bluetooth address to use as its master
+static IOReturn PS3_SetMasterBluetoothAddress(IOHIDDeviceRef inIOHIDDeviceRef, BluetoothDeviceAddress inBluetoothDeviceAddress) {
+ IOReturn result = paramErr;
+ if (inIOHIDDeviceRef) {
+ CFIndex reportID = 0xF5;
+ uint8_t report[8];
+ report[0] = 0x01; report[1] = 0x00;
+ memcpy(&report[2], &inBluetoothDeviceAddress, sizeof(inBluetoothDeviceAddress));
+
+ CFIndex reportSize = sizeof(report);
+ result = IOHIDDeviceSetReport(inIOHIDDeviceRef, kIOHIDReportTypeFeature, reportID, report, reportSize);
+ if (noErr != result) {
+ [target sendDeviceConnectionError:101];
+ printf("%s, IOHIDDeviceSetReport error: %ld (0x%08lX ).\n", __PRETTY_FUNCTION__, (long int) result, (long int) result);
+ }
+ }
+ return(result);
+}
+
+// ask a PS3 IOHIDDevice for its bluetooth address
+static IOReturn PS3_GetDeviceBluetoothAddress(IOHIDDeviceRef inIOHIDDeviceRef, BluetoothDeviceAddress*ioBluetoothDeviceAddress) {
+ IOReturn result = noErr;
+ CFIndex reportID = 0xF2;
+ uint8_t report[17];
+ CFIndex reportSize = sizeof(report);
+ result = IOHIDDeviceGetReport(inIOHIDDeviceRef, kIOHIDReportTypeFeature, reportID, report, &reportSize);
+ if (noErr == result) {
+ if (ioBluetoothDeviceAddress) {
+ memcpy(ioBluetoothDeviceAddress, &report[4], sizeof(*ioBluetoothDeviceAddress));
+ }
+ } else{
+ [target sendDeviceConnectionError:102];
+ }
+ return result;
+}
+
+// tell a PS3 IOHIDDevice to start sending input reports
+static IOReturn PS3_StartInputReports(IOHIDDeviceRef inIOHIDDeviceRef) {
+ uint8_t buffer[5] = {0x42, 0x03, 0x00, 0x00};
+ return(Set_DeviceFeatureReport(inIOHIDDeviceRef, 0xF4, buffer, sizeof(buffer)));
+}
+
+// this will be called when an input report is received
+static void Handle_IOHIDDeviceIOHIDReportCallback(void* inContext, IOReturn inResult, void* inSender, IOHIDReportType inType, uint32_t inReportID, uint8_t* inReport, CFIndex inReportLength) {
+ if(isUseBuffered) {
+ [target parse:inReport l:inReportLength];
+ } else {
+ [target parseUnBuffered:inReport l:inReportLength];
+ }
+
+#ifdef TRACE
+ unsigned char ReportType; //Report Type 01
+ unsigned char Reserved1; // Unknown
+ unsigned char ButtonState; // Main buttons
+ unsigned char PSButtonState; // PS button
+ unsigned char Reserved2; // Unknown
+ unsigned char LeftStickX; // left Joystick X axis 0 - 255, 128 is mid
+ unsigned char LeftStickY; // left Joystick Y axis 0 - 255, 128 is mid
+ unsigned char RightStickX; // right Joystick X axis 0 - 255, 128 is mid
+ unsigned char RightStickY; // right Joystick Y axis 0 - 255, 128 is mid
+ unsigned char Reserved3[4]; // Unknown
+ unsigned char PressureUp; // digital Pad Up button Pressure 0 - 255
+ unsigned char PressureRight; // digital Pad Right button Pressure 0 - 255
+ unsigned char PressureDown; // digital Pad Down button Pressure 0 - 255
+ unsigned char PressureLeft; // digital Pad Left button Pressure 0 - 255
+ unsigned char PressureL2; // digital Pad L2 button Pressure 0 - 255
+ unsigned char PressureR2; // digital Pad R2 button Pressure 0 - 255
+ unsigned char PressureL1; // digital Pad L1 button Pressure 0 - 255
+ unsigned char PressureR1; // digital Pad R1 button Pressure 0 - 255
+ unsigned char PressureTriangle; // digital Pad Triangle button Pressure 0 - 255
+ unsigned char PressureCircle; // digital Pad Circle button Pressure 0 - 255
+ unsigned char PressureCross; // digital Pad Cross button Pressure 0 - 255
+ unsigned char PressureSquare; // digital Pad Square button Pressure 0 - 255
+ unsigned char Reserved4[3]; // Unknown
+ unsigned char Charge; // charging status ? 02 = charge, 03 = normal
+ unsigned char Power; // Battery status ?
+ unsigned char Connection; // Connection Type ?
+ unsigned char Reserved5[9]; // Unknown
+ unsigned int AccelX; // X axis accelerometer Big Endian 0 - 1023
+ unsigned int AccelY; // Y axis accelerometer Big Endian 0 - 1023
+ unsigned int AccelZ; // Z axis accelerometer Big Endian 0 - 1023
+ unsigned int GyroZ;
+
+ // Copy bytes to their respective variables (incase they are not aligned correctly)
+ memcpy( &ReportType, &inReport[1], sizeof( unsigned char ) );
+ memcpy( &Reserved1, &inReport[2], sizeof( unsigned char ) );
+ memcpy( &ButtonState, &inReport[3], sizeof( unsigned char ) );
+ memcpy( &PSButtonState, &inReport[4], sizeof( unsigned char ) );
+ memcpy( &Reserved2, &inReport[5], sizeof( unsigned char ) );
+ memcpy( &LeftStickX, &inReport[6], sizeof( unsigned char ) );
+ memcpy( &LeftStickY, &inReport[7], sizeof( unsigned char ) );
+ memcpy( &RightStickX, &inReport[8], sizeof( unsigned char ) );
+ memcpy( &RightStickY, &inReport[9], sizeof( unsigned char ) );
+ memcpy( &Reserved3, &inReport[10], sizeof( unsigned char ) );
+
+ memcpy( &PressureUp, &inReport[14], sizeof( unsigned char ) );
+ memcpy( &PressureRight, &inReport[15], sizeof( unsigned char ) );
+ memcpy( &PressureDown, &inReport[16], sizeof( unsigned char ) );
+ memcpy( &PressureLeft, &inReport[17], sizeof( unsigned char ) );
+ memcpy( &PressureL2, &inReport[18], sizeof( unsigned char ) );
+ memcpy( &PressureR2, &inReport[19], sizeof( unsigned char ) );
+ memcpy( &PressureL1, &inReport[20], sizeof( unsigned char ) );
+ memcpy( &PressureR1, &inReport[21], sizeof( unsigned char ) );
+
+ memcpy( &PressureTriangle, &inReport[22], sizeof( unsigned char ) );
+ memcpy( &PressureCircle, &inReport[23], sizeof( unsigned char ) );
+ memcpy( &PressureCross, &inReport[24], sizeof( unsigned char ) );
+ memcpy( &PressureSquare, &inReport[25], sizeof( unsigned char ) );
+
+ memcpy( &Reserved4, &inReport[30], sizeof( unsigned char ) );
+ memcpy( &Charge, &inReport[31], sizeof( unsigned char ) );
+ memcpy( &Power, &inReport[32], sizeof( unsigned char ) );
+ memcpy( &Connection, &inReport[33], sizeof( unsigned char ) );
+ memcpy( &Reserved5, &inReport[34], sizeof( unsigned char ) );
+ memcpy( &AccelX, &inReport[43], sizeof( unsigned int ) );
+ memcpy( &AccelY, &inReport[44], sizeof( unsigned int ) );
+ memcpy( &AccelZ, &inReport[45], sizeof( unsigned int ) );
+ memcpy( &GyroZ, &inReport[46], sizeof( unsigned int ) );
+#endif
+}
+
+static Boolean IOHIDDevice_GetLongProperty_( IOHIDDeviceRef inIOHIDDeviceRef, CFStringRef inKey, long * outValue ) {
+ Boolean result = FALSE;
+ if (inIOHIDDeviceRef) {
+ assert( IOHIDDeviceGetTypeID() == CFGetTypeID( inIOHIDDeviceRef ) );
+ CFTypeRef tCFTypeRef = IOHIDDeviceGetProperty( inIOHIDDeviceRef, inKey );
+ if ( tCFTypeRef ) {
+ // if this is a number
+ if ( CFNumberGetTypeID() == CFGetTypeID( tCFTypeRef ) ) {
+ // get it's value
+ result = CFNumberGetValue( ( CFNumberRef ) tCFTypeRef, kCFNumberSInt32Type, outValue );
+ }
+ }
+ }
+ return result;
+}
+
+long IOHIDDevice_GetVendorID_( IOHIDDeviceRef inIOHIDDeviceRef ) {
+ long result = 0;
+ ( void ) IOHIDDevice_GetLongProperty_( inIOHIDDeviceRef, CFSTR( kIOHIDVendorIDKey ), &result );
+ return result;
+}
+
+long IOHIDDevice_GetProductID_( IOHIDDeviceRef inIOHIDDeviceRef ) {
+ long result = 0;
+ ( void ) IOHIDDevice_GetLongProperty_( inIOHIDDeviceRef, CFSTR( kIOHIDProductIDKey ), &result );
+ return result;
+}
+
+// this will be called when the HID Manager matches a new (hot plugged) HID device
+static void Handle_DeviceMatchingCallback(void* inContext, IOReturn inResult, void* inSender, IOHIDDeviceRef inIOHIDDeviceRef) {
+
+ IOReturn ioReturn = noErr;
+
+ // Device VendorID/ProductID: 0x054C/0x0268 (Sony Corporation)
+ long vendorID = IOHIDDevice_GetVendorID_(inIOHIDDeviceRef);
+ long productID = IOHIDDevice_GetProductID_(inIOHIDDeviceRef);
+
+ // Sony PlayStation(R)3 Controller
+ if ((0x054C != vendorID) || (0x0268 != productID)) {
+ return;
+ }
+ gIOHIDDeviceRef = inIOHIDDeviceRef;
+
+ if (doBluetooth) {
+#if DO_BLUETOOTH
+ Boolean devicesMasterBluetoothAddressValid = FALSE;
+ Boolean masterBluetoothAddressesMatch = TRUE;
+
+ BluetoothDeviceAddress tBtDeviceAddr;
+ ioReturn = PS3_GetMasterBluetoothAddress(inIOHIDDeviceRef, &tBtDeviceAddr);
+
+ if (noErr == ioReturn) {
+ devicesMasterBluetoothAddressValid = TRUE;
+ //printf("<%02hX-%02hX-%02hX-%02hX-%02hX-%02hX>\n", tBtDeviceAddr.data[0], tBtDeviceAddr.data[1],tBtDeviceAddr.data[2], tBtDeviceAddr.data[3], tBtDeviceAddr.data[4],tBtDeviceAddr.data[5]);
+ masterBluetoothAddressesMatch = TRUE;
+ int idx;
+ for (idx = 0; idx < 6; idx++) {
+ if (tBtDeviceAddr.data[idx] != gMasterBluetoothAddress.data[idx]) {
+ masterBluetoothAddressesMatch = FALSE;
+ break;
+ }
+ }
+
+ if (!masterBluetoothAddressesMatch) {
+ [target sendDeviceConnectionError:103];
+ }
+ } else {
+ [target sendDeviceConnectionError:104];
+ //printf("%s, PS3_GetMasterBluetoothAddress error: %ld (0x%08lX ).\n", __PRETTY_FUNCTION__, (long int) ioReturn, (long int) ioReturn);
+ }
+ {
+ //printf(" Getting devices current Bluetooth address\n");
+ BluetoothDeviceAddress tBtDeviceAddr;
+ IOReturn ioReturn = PS3_GetDeviceBluetoothAddress(inIOHIDDeviceRef, &tBtDeviceAddr);
+
+ if (noErr == ioReturn) {
+ //printf("<%02hX-%02hX-%02hX-%02hX-%02hX-%02hX>\n",tBtDeviceAddr.data[0], tBtDeviceAddr.data[1], tBtDeviceAddr.data[2], tBtDeviceAddr.data[3],tBtDeviceAddr.data[4],tBtDeviceAddr.data[5]);
+ }
+ }
+#endif // DO_BLUETOOTH
+
+#if (DO_BLUETOOTH && DO_SET_MASTER)
+ do {
+ if (!gMasterBluetoothAddressValid) {
+ //printf(" NO BLUETOOTH!\n");
+ [target sendDeviceConnectionError:105];
+ break;
+ }
+
+ if (devicesMasterBluetoothAddressValid && !masterBluetoothAddressesMatch) {
+ //printf(" Setting devices master Bluetooth address\n");
+ ioReturn = PS3_SetMasterBluetoothAddress(inIOHIDDeviceRef, gMasterBluetoothAddress);
+
+ if (noErr == ioReturn) {
+ //printf(" Getting devices current master Bluetooth address\n");
+ BluetoothDeviceAddress tBtDeviceAddr;
+ IOReturn ioReturn = PS3_GetMasterBluetoothAddress(inIOHIDDeviceRef, &tBtDeviceAddr);
+
+ if (noErr == ioReturn) {
+ //printf("<%02hX-%02hX-%02hX-%02hX-%02hX-%02hX>\n",tBtDeviceAddr.data[0],tBtDeviceAddr.data[1], tBtDeviceAddr.data[2], tBtDeviceAddr.data[3],tBtDeviceAddr.data[4],tBtDeviceAddr.data[5]);
+ masterBluetoothAddressesMatch = TRUE;
+ int idx;
+
+ for (idx = 0; idx < 6; idx++) {
+ if (tBtDeviceAddr.data[idx] != gMasterBluetoothAddress.data[idx]) {
+ masterBluetoothAddressesMatch = FALSE;
+ break;
+ }
+ }
+ }
+ } else {
+ //printf("%s, PS3_SetMasterBluetoothAddress error: %ld (0x%08lX ).\n", __PRETTY_FUNCTION__, (long int) ioReturn, (long int) ioReturn);
+ [target sendDeviceConnectionError:106];
+ }
+ }
+ } while (0);
+#endif // ( DO_BLUETOOTH && DO_SET_MASTER )
+ }
+
+ CFIndex reportSize = 64;
+ uint8_t*report = malloc(reportSize);
+ IOHIDDeviceRegisterInputReportCallback(inIOHIDDeviceRef, report, reportSize, Handle_IOHIDDeviceIOHIDReportCallback, nil);
+
+ [target sendDeviceConnected];
+}
+
+// this will be called when a HID device is removed (unplugged)
+static void Handle_RemovalCallback(void* inContext, IOReturn inResult, void* inSender, IOHIDDeviceRef inIOHIDDeviceRef) {
+ if (gIOHIDDeviceRef == inIOHIDDeviceRef) {
+ gIOHIDDeviceRef = NULL;
+ [target sendDeviceDisconnected];
+ }
+}
+
+-(void)sendDeviceConnected {
+ isConnected = YES;
+ if ([delegate respondsToSelector:@selector(onDeviceConnected)]) {
+ [delegate onDeviceConnected];
+ }
+}
+
+-(void)sendDeviceDisconnected {
+ isConnected = NO;
+ [self disconnect];
+ if ([delegate respondsToSelector:@selector(onDeviceDisconnected)]) {
+ [delegate onDeviceDisconnected];
+ }
+}
+
+-(void)sendDeviceConnectionError:(NSInteger)error {
+ isConnected = NO;
+ if ([delegate respondsToSelector:@selector(onDeviceConnectionError:)]) {
+ [delegate onDeviceConnectionError:error];
+ }
+}
+
+- (void) parseUnBuffered:(uint8_t*)data l:(CFIndex)length {
+
+}
+
+-(void)parse:(uint8_t*)data l:(CFIndex)length {
+#pragma mark ButtonStates
+ //unsigned char ButtonState;
+ //memcpy( &ButtonState, &data[3], sizeof( unsigned char ) );
+ //printf("data[3] %u\n", data[3]);
+ switch (data[3]) {
+ case kButtonsRelease:
+ // release all Buttons
+ isTriangleButtonDown = NO;
+ isCircleButtonDown = NO;
+ isCrossButtonDown = NO;
+ isSquareButtonDown = NO;
+ isL1ButtonDown = NO;
+ isL2ButtonDown = NO;
+ isR1ButtonDown = NO;
+ isR2ButtonDown = NO;
+ break;
+ case kTriangleButton:
+ isTriangleButtonDown = YES;
+ isCircleButtonDown = NO;
+ isCrossButtonDown = NO;
+ isSquareButtonDown = NO;
+ break;
+ case kTriangleAndCircleButton:
+ isTriangleButtonDown = YES;
+ isCircleButtonDown = YES;
+ isCrossButtonDown = NO;
+ isSquareButtonDown = NO;
+ break;
+ case kTriangleAndCrossButton:
+ isTriangleButtonDown = YES;
+ isCircleButtonDown = NO;
+ isCrossButtonDown = YES;
+ isSquareButtonDown = NO;
+ break;
+ case kTriangleAndSquareButton:
+ isTriangleButtonDown = YES;
+ isCircleButtonDown = NO;
+ isCrossButtonDown = NO;
+ isSquareButtonDown = YES;
+ break;
+ case kCircleButton:
+ isTriangleButtonDown = NO;
+ isCircleButtonDown = YES;
+ isCrossButtonDown = NO;
+ isSquareButtonDown = NO;
+ break;
+ case kCircleAndCrossButton:
+ isTriangleButtonDown = NO;
+ isCircleButtonDown = YES;
+ isCrossButtonDown = YES;
+ isSquareButtonDown = NO;
+ break;
+ case kCircleAndSquareButton:
+ isTriangleButtonDown = NO;
+ isCircleButtonDown = YES;
+ isCrossButtonDown = NO;
+ isSquareButtonDown = YES;
+ break;
+ case kCrossButton:
+ isTriangleButtonDown = NO;
+ isCircleButtonDown = NO;
+ isCrossButtonDown = YES;
+ isSquareButtonDown = NO;
+ break;
+ case kCrossAndSquareButton:
+ isTriangleButtonDown = NO;
+ isCircleButtonDown = NO;
+ isCrossButtonDown = YES;
+ isSquareButtonDown = YES;
+ break;
+ case kSquareButton:
+ isTriangleButtonDown = NO;
+ isCircleButtonDown = NO;
+ isCrossButtonDown = NO;
+ isSquareButtonDown = YES;
+ break;
+ case kTriangleAndCircleAndCrossButton:
+ isTriangleButtonDown = YES;
+ isCircleButtonDown = YES;
+ isCrossButtonDown = YES;
+ isSquareButtonDown = NO;
+ break;
+ case kTriangleAndSquareAndCircleButton:
+ isTriangleButtonDown = YES;
+ isCircleButtonDown = YES;
+ isCrossButtonDown = NO;
+ isSquareButtonDown = YES;
+ break;
+ case kCrossAndSquareAndTriangleButton:
+ isTriangleButtonDown = YES;
+ isCircleButtonDown = NO;
+ isCrossButtonDown = YES;
+ isSquareButtonDown = YES;
+ break;
+ case kCircleAndCrossAndSquareButton:
+ isTriangleButtonDown = NO;
+ isCircleButtonDown = YES;
+ isCrossButtonDown = YES;
+ isSquareButtonDown = YES;
+ break;
+ case kCircleAndCrossAndSquareAndTriangleButton:
+ isTriangleButtonDown = YES;
+ isCircleButtonDown = YES;
+ isCrossButtonDown = YES;
+ isSquareButtonDown = YES;
+ break;
+ case kL1:
+ isL1ButtonDown = YES;
+ isL2ButtonDown = NO;
+ isR1ButtonDown = NO;
+ isR2ButtonDown = NO;
+ break;
+ case kL2:
+ isL1ButtonDown = NO;
+ isL2ButtonDown = YES;
+ isR1ButtonDown = NO;
+ isR2ButtonDown = NO;
+ break;
+ case kR1:
+ isL1ButtonDown = NO;
+ isL2ButtonDown = NO;
+ isR1ButtonDown = YES;
+ isR2ButtonDown = NO;
+ break;
+ case kR2:
+ isL1ButtonDown = NO;
+ isL2ButtonDown = NO;
+ isR1ButtonDown = NO;
+ isR2ButtonDown = YES;
+ break;
+ case kL2R2:
+ isL1ButtonDown = NO;
+ isL2ButtonDown = YES;
+ isR1ButtonDown = NO;
+ isR2ButtonDown = YES;
+ break;
+ case kL1L2:
+ isL1ButtonDown = YES;
+ isL2ButtonDown = YES;
+ isR1ButtonDown = NO;
+ isR2ButtonDown = NO;
+ break;
+ case kL1R2:
+ isL1ButtonDown = YES;
+ isL2ButtonDown = NO;
+ isR1ButtonDown = NO;
+ isR2ButtonDown = YES;
+ break;
+ case kL1L2R2:
+ isL1ButtonDown = YES;
+ isL2ButtonDown = YES;
+ isR1ButtonDown = NO;
+ isR2ButtonDown = YES;
+ break;
+ case kR1L2:
+ isL1ButtonDown = NO;
+ isL2ButtonDown = YES;
+ isR1ButtonDown = YES;
+ isR2ButtonDown = NO;
+ break;
+ case kR1R2:
+ isL1ButtonDown = NO;
+ isL2ButtonDown = NO;
+ isR1ButtonDown = YES;
+ isR2ButtonDown = YES;
+ break;
+ case kR1R2L2:
+ isL1ButtonDown = NO;
+ isL2ButtonDown = YES;
+ isR1ButtonDown = YES;
+ isR2ButtonDown = YES;
+ break;
+ case kL1R1:
+ isL1ButtonDown = YES;
+ isL2ButtonDown = NO;
+ isR1ButtonDown = YES;
+ isR2ButtonDown = NO;
+ break;
+ case kL1L2R1:
+ isL1ButtonDown = YES;
+ isL2ButtonDown = YES;
+ isR1ButtonDown = YES;
+ isR2ButtonDown = NO;
+ break;
+ case kL1R1R2:
+ isL1ButtonDown = YES;
+ isL2ButtonDown = NO;
+ isR1ButtonDown = YES;
+ isR2ButtonDown = YES;
+ break;
+ case kL1L2R1R2:
+ isL1ButtonDown = YES;
+ isL2ButtonDown = YES;
+ isR1ButtonDown = YES;
+ isR2ButtonDown = YES;
+ break;
+ default:
+ break;
+ }
+#pragma mark DirectionButtons
+ //unsigned char DirectionButtonState;
+ //memcpy( &DirectionButtonState, &data[2], sizeof( unsigned char ) );
+ //printf( "DirectionButtonState: %u\n", data[2] );
+ switch (data[2]) {
+ case kDirectionButtonsRelease:
+ // release all Buttons
+ isNorthButtonDown = NO;
+ isEastButtonDown = NO;
+ isSouthButtonDown = NO;
+ isWestButtonDown = NO;
+ isLeftStickDown = NO;
+ isRightStickDown = NO;
+ isSelectButtonDown = NO;
+ isStartButtonDown = NO;
+ break;
+ case kNorthButton:
+ isNorthButtonDown = YES;
+ isEastButtonDown = NO;
+ isSouthButtonDown = NO;
+ isWestButtonDown = NO;
+ break;
+ case kEastButton:
+ isNorthButtonDown = NO;
+ isEastButtonDown = YES;
+ isSouthButtonDown = NO;
+ isWestButtonDown = NO;
+ break;
+ case kSouthButton:
+ isNorthButtonDown = NO;
+ isEastButtonDown = NO;
+ isSouthButtonDown = YES;
+ isWestButtonDown = NO;
+ break;
+ case kWestButton:
+ isNorthButtonDown = NO;
+ isEastButtonDown = NO;
+ isSouthButtonDown = NO;
+ isWestButtonDown = YES;
+ break;
+ case kNorthEastButton:
+ isNorthButtonDown = YES;
+ isEastButtonDown = YES;
+ isSouthButtonDown = NO;
+ isWestButtonDown = NO;
+ break;
+ case kEastSouthButton:
+ isNorthButtonDown = NO;
+ isEastButtonDown = YES;
+ isSouthButtonDown = YES;
+ isWestButtonDown = NO;
+ break;
+ case kWestNorthButton:
+ isNorthButtonDown = YES;
+ isEastButtonDown = NO;
+ isSouthButtonDown = NO;
+ isWestButtonDown = YES;
+ break;
+ case kWestSouthButton:
+ isNorthButtonDown = NO;
+ isEastButtonDown = NO;
+ isSouthButtonDown = YES;
+ isWestButtonDown = YES;
+ break;
+ case kLeftStickButton:
+ isLeftStickDown = YES;
+ break;
+ case kRightStickButton:
+ isRightStickDown = YES;
+ break;
+ case kLeftAndRightStickButton:
+ isLeftStickDown = YES;
+ isRightStickDown = YES;
+ break;
+ case kSelectButton:
+ isSelectButtonDown = YES;
+ break;
+ case kStartButton:
+ isStartButtonDown = YES;
+ break;
+ case kSelectAndStartButton:
+ isSelectButtonDown = YES;
+ isStartButtonDown = YES;
+ break;
+ default:
+ break;
+ }
+
+#pragma mark select and start button
+ if (isSelectButtonDown != preIsSelectButtonDown) {
+ if ([delegate respondsToSelector:@selector(onSelectButton:)]) {
+ [delegate onSelectButton:isSelectButtonDown];
+ }
+ preIsSelectButtonDown = isSelectButtonDown;
+ }
+ if (isStartButtonDown != preIsStartButtonDown) {
+ if ([delegate respondsToSelector:@selector(onStartButton:)]) {
+ [delegate onStartButton:isStartButtonDown];
+ }
+ preIsStartButtonDown = isStartButtonDown;
+ }
+
+#pragma mark PSButton
+ //unsigned char PSButtonState;
+ //memcpy( &PSButtonState, &data[4], sizeof( unsigned char ) );
+ BOOL psb = (BOOL)data[4];
+ if (psb != preIsPSButtonDown) {
+ if ([delegate respondsToSelector:@selector(onPSButton:)]) {
+ [delegate onPSButton:psb];
+ }
+ preIsPSButtonDown = psb;
+ }
+
+#pragma mark LeftStick
+ /*
+ unsigned char LeftStickX; // left Joystick X axis 0 - 255, 128 is mid
+ unsigned char LeftStickY; // left Joystick Y axis 0 - 255, 128 is mid
+ memcpy( &LeftStickX, &data[6], sizeof( unsigned char ) );
+ memcpy( &LeftStickY, &data[7], sizeof( unsigned char ) );
+ int leftStickX = (int)LeftStickX;
+ int leftStickY = (int)LeftStickY;
+ */
+ int leftStickX = (int)data[6];
+ int leftStickY = (int)data[7];
+ if ((leftStickX != preLeftStickX) && (leftStickY != preLeftStickY)) {
+ /*
+ if ((preLeftStickX < 125 || preLeftStickX > 131) && (preLeftStickY < 125 || preLeftStickY > 131)) {
+
+ } else {
+ preLeftStickX = 128;
+ preLeftStickY = 128;
+ }
+ */
+ //printf( "LeftStick: %d, %d\n", (int)LeftStickX, (int)LeftStickY );
+ if ([delegate respondsToSelector:@selector(onLeftStick:pressed:)]) {
+ [delegate onLeftStick:NSMakePoint((float)data[6], (float)data[7]) pressed:isLeftStickDown];
+ }
+ preLeftStickX = leftStickX;
+ preLeftStickY = leftStickY;
+ }
+
+#pragma mark RightStick
+ /*
+ unsigned char RightStickX; // right Joystick X axis 0 - 255, 128 is mid
+ unsigned char RightStickY; // right Joystick Y axis 0 - 255, 128 is mid
+ memcpy( &RightStickX, &data[8], sizeof( unsigned char ) );
+ memcpy( &RightStickY, &data[9], sizeof( unsigned char ) );
+ int rsx = (int)RightStickX;
+ int rsy = (int)RightStickY;
+ */
+ int rsx = (int)data[8];
+ int rsy = (int)data[9];
+ if ((rsx != preRightStickX) && (rsy != preRightStickY)) {
+ /*
+ if ((preRightStickX < 125 || preRightStickX > 131) && (preRightStickY < 125 || preRightStickY > 131)) {
+
+ } else {
+ preRightStickX = 128;
+ preRightStickY = 128;
+ }
+ */
+ //printf( "RightStick: %d, %d\n", (int)RightStickX, (int)RightStickY );
+ if ([delegate respondsToSelector:@selector(onRightStick:pressed:)]) {
+ [delegate onRightStick:NSMakePoint((float)data[8], (float)data[9]) pressed:isRightStickDown];
+ }
+ preRightStickX = rsx;
+ preRightStickY = rsy;
+ }
+
+#pragma mark Buttons
+ // digital Pad Triangle button Trigger
+ if(isTriangleButtonDown != preIsTriangleButtonDown) {
+ if (!isTriangleButtonDown && [delegate respondsToSelector:@selector(onTriangleButtonWithPressure:)]) {
+ [delegate onTriangleButtonWithPressure:0];
+ }
+ if ([delegate respondsToSelector:@selector(onTriangleButton:)]) {
+ [delegate onTriangleButton:isTriangleButtonDown];
+ }
+ preIsTriangleButtonDown = isTriangleButtonDown;
+ }
+ // digital Pad Triangle button Pressure 0 - 255
+ if(isTriangleButtonDown) {
+ if ([delegate respondsToSelector:@selector(onTriangleButtonWithPressure:)]) {
+ //unsigned char PressureTriangle;
+ //memcpy( &PressureTriangle, &data[22], sizeof( unsigned char ) );
+ [delegate onTriangleButtonWithPressure:(NSInteger)data[22]];
+ }
+ }
+ // digital Pad Circle button Trigger
+ if(isCircleButtonDown != preIsCircleButtonDown) {
+ if (!isCircleButtonDown && [delegate respondsToSelector:@selector(onCircleButtonWithPressure:)]) {
+ [delegate onCircleButtonWithPressure:0];
+ }
+ if ([delegate respondsToSelector:@selector(onCircleButton:)]) {
+ [delegate onCircleButton:isCircleButtonDown];
+ }
+ preIsCircleButtonDown = isCircleButtonDown;
+ }
+ // digital Pad Circle button Pressure 0 - 255
+ if(isCircleButtonDown) {
+ if ([delegate respondsToSelector:@selector(onCircleButtonWithPressure:)]) {
+ //unsigned char PressureCircle;
+ //memcpy( &PressureCircle, &data[23], sizeof( unsigned char ) );
+ [delegate onCircleButtonWithPressure:(NSInteger)data[23]];
+ }
+ }
+
+ // Cross Button
+ // digital Pad Cross button Trigger
+ if(isCrossButtonDown != preIsCrossButtonDown) {
+ if (!isCrossButtonDown && [delegate respondsToSelector:@selector(onCrossButtonWithPressure:)]) {
+ [delegate onCrossButtonWithPressure:0];
+ }
+ if ([delegate respondsToSelector:@selector(onCrossButton:)]) {
+ [delegate onCrossButton:isCrossButtonDown];
+ }
+ preIsCrossButtonDown = isCrossButtonDown;
+ }
+ // digital Pad Cross button Pressure 0 - 255
+ if(isCrossButtonDown) {
+ if ([delegate respondsToSelector:@selector(onCrossButtonWithPressure:)]) {
+ //unsigned char PressureCross;
+ //memcpy( &PressureCross, &data[24], sizeof( unsigned char ) );
+ [delegate onCrossButtonWithPressure:(NSInteger)data[24]];
+ }
+ }
+
+ // Square Button
+ // digital Pad Square button Trigger
+ if(isSquareButtonDown != preIsSquareButtonDown) {
+ if (!isSquareButtonDown && [delegate respondsToSelector:@selector(onSquareButtonWithPressure:)]) {
+ [delegate onSquareButtonWithPressure:0];
+ }
+ if ([delegate respondsToSelector:@selector(onSquareButton:)]) {
+ [delegate onSquareButton:isSquareButtonDown];
+ }
+ preIsSquareButtonDown = isSquareButtonDown;
+ }
+ // digital Pad Square button Pressure 0 - 255
+ if(isSquareButtonDown) {
+ if ([delegate respondsToSelector:@selector(onSquareButtonWithPressure:)]) {
+ //unsigned char PressureSquare;
+ //memcpy( &PressureSquare, &data[25], sizeof( unsigned char ) );
+ [delegate onSquareButtonWithPressure:(NSInteger)data[25]];
+ }
+ }
+
+ // L2 Button
+ // digital Pad L2 button Trigger
+ if(isL2ButtonDown != preIsL2ButtonDown) {
+ if (!isL2ButtonDown && [delegate respondsToSelector:@selector(onL2ButtonWithPressure:)]) {
+ [delegate onL2ButtonWithPressure:0];
+ }
+ if ([delegate respondsToSelector:@selector(onL2Button:)]) {
+ [delegate onL2Button:isL2ButtonDown];
+ }
+ preIsL2ButtonDown = isL2ButtonDown;
+ }
+ // digital Pad L2 button Pressure 0 - 255
+ if(isL2ButtonDown) {
+ if ([delegate respondsToSelector:@selector(onL2ButtonWithPressure:)]) {
+ //unsigned char PressureL2;
+ //memcpy( &PressureL2, &data[18], sizeof( unsigned char ) );
+ [delegate onL2ButtonWithPressure:(NSInteger)data[18]];
+ }
+ }
+
+ // R2 Button
+ // digital Pad R2 button Trigger
+ if(isR2ButtonDown != preIsR2ButtonDown) {
+ if (!isR2ButtonDown && [delegate respondsToSelector:@selector(onR2ButtonWithPressure:)]) {
+ [delegate onR2ButtonWithPressure:0];
+ }
+ if ([delegate respondsToSelector:@selector(onR2Button:)]) {
+ [delegate onR2Button:isR2ButtonDown];
+ }
+ preIsR2ButtonDown = isR2ButtonDown;
+ }
+ // digital Pad R2 button Pressure 0 - 255
+ if(isR2ButtonDown) {
+ if ([delegate respondsToSelector:@selector(onR2ButtonWithPressure:)]) {
+ //unsigned char PressureR2;
+ //memcpy( &PressureR2, &data[19], sizeof( unsigned char ) );
+ [delegate onR2ButtonWithPressure:(NSInteger)data[19]];
+ }
+ }
+
+ // L1 Button
+ // digital Pad L1 button Trigger
+ if(isL1ButtonDown != preIsL1ButtonDown) {
+ if (!isL1ButtonDown && [delegate respondsToSelector:@selector(onL1ButtonWithPressure:)]) {
+ [delegate onL1ButtonWithPressure:0];
+ }
+ if ([delegate respondsToSelector:@selector(onL1Button:)]) {
+ [delegate onL1Button:isL1ButtonDown];
+ }
+ preIsL1ButtonDown = isL1ButtonDown;
+ }
+ // digital Pad L1 button Pressure 0 - 255
+ if(isL1ButtonDown) {
+ if ([delegate respondsToSelector:@selector(onL1ButtonWithPressure:)]) {
+ //unsigned char PressureL1;
+ //memcpy( &PressureL1, &data[20], sizeof( unsigned char ) );
+ [delegate onL1ButtonWithPressure:(NSInteger)data[20]];
+ }
+ }
+
+ // R1 Button
+ // digital Pad R1 button Trigger
+ if(isR1ButtonDown != preIsR1ButtonDown) {
+ if (!isR1ButtonDown && [delegate respondsToSelector:@selector(onR1ButtonWithPressure:)]) {
+ [delegate onR1ButtonWithPressure:0];
+ }
+ if ([delegate respondsToSelector:@selector(onR1Button:)]) {
+ [delegate onR1Button:isR1ButtonDown];
+ }
+ preIsR1ButtonDown = isR1ButtonDown;
+ }
+ // digital Pad R1 button Pressure 0 - 255
+ if(isR1ButtonDown) {
+ if ([delegate respondsToSelector:@selector(onR1ButtonWithPressure:)]) {
+ //unsigned char PressureR1;
+ //memcpy( &PressureR1, &data[21], sizeof( unsigned char ) );
+ [delegate onR1ButtonWithPressure:(NSInteger)data[21]];
+ }
+ }
+
+ // North Button
+ // Cross North button Trigger
+ if(isNorthButtonDown != preIsNorthButtonDown) {
+ if (!isNorthButtonDown && [delegate respondsToSelector:@selector(onNorthButtonWithPressure:)]) {
+ [delegate onNorthButtonWithPressure:0];
+ }
+ if ([delegate respondsToSelector:@selector(onNorthButton:)]) {
+ [delegate onNorthButton:isNorthButtonDown];
+ }
+ preIsNorthButtonDown = isNorthButtonDown;
+ }
+ // Cross North button Pressure 0 - 255
+ if(isNorthButtonDown) {
+ if ([delegate respondsToSelector:@selector(onNorthButtonWithPressure:)]) {
+ //unsigned char PressureNorth;
+ //memcpy( &PressureNorth, &data[14], sizeof( unsigned char ) );
+ [delegate onNorthButtonWithPressure:(NSInteger)data[14]];
+ }
+ }
+
+ // East Button
+ // Cross East button Trigger
+ if(isEastButtonDown != preIsEastButtonDown) {
+ if (!isEastButtonDown && [delegate respondsToSelector:@selector(onEastButtonWithPressure:)]) {
+ [delegate onEastButtonWithPressure:0];
+ }
+ if ([delegate respondsToSelector:@selector(onEastButton:)]) {
+ [delegate onEastButton:isEastButtonDown];
+ }
+ preIsEastButtonDown = isEastButtonDown;
+ }
+ // Cross East button Pressure 0 - 255
+ if(isEastButtonDown) {
+ if ([delegate respondsToSelector:@selector(onEastButtonWithPressure:)]) {
+ //unsigned char PressureEast;
+ //memcpy( &PressureEast, &data[15], sizeof( unsigned char ) );
+ [delegate onEastButtonWithPressure:(NSInteger)data[15]];
+ }
+ }
+
+ // South Button
+ // Cross South button Trigger
+ if(isSouthButtonDown != preIsSouthButtonDown) {
+ if (!isSouthButtonDown && [delegate respondsToSelector:@selector(onSouthButtonWithPressure:)]) {
+ [delegate onSouthButtonWithPressure:0];
+ }
+ if ([delegate respondsToSelector:@selector(onSouthButton:)]) {
+ [delegate onSouthButton:isSouthButtonDown];
+ }
+ preIsSouthButtonDown = isSouthButtonDown;
+ }
+ // Cross South button Pressure 0 - 255
+ if(isSouthButtonDown) {
+ if ([delegate respondsToSelector:@selector(onSouthButtonWithPressure:)]) {
+ //unsigned char PressureSouth;
+ //memcpy( &PressureSouth, &data[16], sizeof( unsigned char ) );
+ [delegate onSouthButtonWithPressure:(NSInteger)data[16]];
+ }
+ }
+
+ // West Button
+ // Cross West button Trigger
+ if(isWestButtonDown != preIsWestButtonDown) {
+ if (!isWestButtonDown && [delegate respondsToSelector:@selector(onWestButtonWithPressure:)]) {
+ [delegate onWestButtonWithPressure:0];
+ }
+ if ([delegate respondsToSelector:@selector(onWestButton:)]) {
+ [delegate onWestButton:isWestButtonDown];
+ }
+ preIsWestButtonDown = isWestButtonDown;
+ }
+ // Cross West button Pressure 0 - 255
+ if(isWestButtonDown) {
+ if ([delegate respondsToSelector:@selector(onWestButtonWithPressure:)]) {
+ //unsigned char PressureWest;
+ //memcpy( &PressureWest, &data[17], sizeof( unsigned char ) );
+ [delegate onWestButtonWithPressure:(NSInteger)data[17]];
+ }
+ }
+
+ /*
+ Accelerometer data
+ Field Example Purpose Note
+ 1 0208 accX / sin(roll) On my sixaxis, +11 is rest, +126 is 90deg left, -100 is 90deg right
+ 2 01f2 accY / sin(pitch) On my sixaxis, -19 is rest, -117 is 90deg nose down, +114 is 90deg, controls facing you
+ 3 0193 accZ / gravity On my sixaxis, sat on the table is -93, upside down is 131
+ */
+ /*
+ unsigned char ax1;
+ unsigned char ax2;
+ unsigned char ay1;
+ unsigned char ay2;
+ unsigned char az1;
+ unsigned char az2;
+ memcpy( &ax1, &data[40], sizeof( unsigned char ) );
+ memcpy( &ax2, &data[41], sizeof( unsigned char ) );
+ memcpy( &ay1, &data[42], sizeof( unsigned char ) );
+ memcpy( &ay2, &data[43], sizeof( unsigned char ) );
+ memcpy( &az1, &data[44], sizeof( unsigned char ) );
+ memcpy( &az2, &data[45], sizeof( unsigned char ) );
+ */
+ /* Accelerometers */
+
+ /*
+ *(uint16_t *)&data[40] = htons(clamp(0, mx + 512, 1023));
+ *(uint16_t *)&data[42] = htons(clamp(0, my + 512, 1023));
+ *(uint16_t *)&data[44] = htons(clamp(0, mz + 512, 1023));
+
+ mx = ntohs(*(uint16_t *)&data[40]) - 512;
+ my = ntohs(*(uint16_t *)&data[42]) - 512;
+ mz = ntohs(*(uint16_t *)&data[44]) - 512;
+ */
+ mx = data[40] | (data[41] << 8);
+ my = data[42] | (data[43] << 8);
+ mz = data[44] | (data[45] << 8);
+// *(uint16_t *)&data[46] = htons(clamp(0, u->accel.gyro + 512, 1023));
+
+
+ //memcpy( &GyroZ, &data[46], sizeof( long int ) );
+ //#define byteswap(x) ((x >> 8) | (x << 8))
+ //int ax = (ax1 >> 8) | (ax2 << 8);
+ //int ay = (ay1 >> 8) | (ay2 << 8);
+ //int az = (az1 >> 8) | (az2 << 8);
+ //char ax = byteswap(ax2) + ax1;
+ //char ay = byteswap(ay2) + ay1;
+ //char az = byteswap(az2) + az1;
+ //int rz = data[46]<<8 | data[47]; // Needs another patch.
+
+ if ([delegate respondsToSelector:@selector(onAxisX:Y:Z:)]) {
+ [delegate onAxisX:mx Y:my Z:mz];
+ }
+}
+
+int clamp(int min, int val, int max)
+{
+ if (val < min) return min;
+ if (val > max) return max;
+ return val;
+}
+
+@end
+
+@implementation PS3SixAxis
+
++ (id)sixAixisController {
+ return [[self alloc] init];
+}
+
++ (id)sixAixisControllerWithDelegate:(id<PS3SixAxisDelegate>)aDelegate {
+ return [[self alloc] initSixAixisControllerWithDelegate:aDelegate];
+}
+
+- (id) initSixAixisControllerWithDelegate:(id<PS3SixAxisDelegate>)aDelegate {
+ self = [self init];
+ if (self) {
+ delegate = aDelegate;
+ }
+ return self;
+}
+
+- (id) init {
+ self = [super init];
+ if(self) {
+ target = self;
+ }
+ return self;
+}
+
+- (void) connect:(BOOL)enableBluetooth {
+
+ if (hidManagerRef) {
+ if(isConnected) {
+ if ([delegate respondsToSelector:@selector(onDeviceConnected)]) {
+ [delegate onDeviceConnected];
+ }
+ }
+ return;
+ }
+
+ int error = 0;
+
+ if(enableBluetooth) {
+ IOBluetoothHostController*defaultController = [IOBluetoothHostController defaultController];
+ if (!defaultController) {
+ error = 1;
+ }
+
+ if ([defaultController getAddress:&gMasterBluetoothAddress] != kIOReturnSuccess) {
+ error = 2;
+ }
+ gMasterBluetoothAddressValid = TRUE;
+ }
+
+ doBluetooth = enableBluetooth;
+ if (enableBluetooth && error != 0) {
+ if ([delegate respondsToSelector:@selector(onDeviceConnectionError:)]) {
+ [delegate onDeviceConnectionError:error];
+ }
+ return;
+ }
+
+ hidManagerRef = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone);
+ if (hidManagerRef) {
+ // match all devices
+ IOHIDManagerSetDeviceMatching(hidManagerRef, NULL);
+
+ // Register device matching callback routine
+ // This routine will be called when a new (matching) device is connected.
+ IOHIDManagerRegisterDeviceMatchingCallback(hidManagerRef, Handle_DeviceMatchingCallback, self);
+
+ // Registers a routine to be called when any currently enumerated device is removed.
+ // This routine will be called when a (matching) device is disconnected.
+ IOHIDManagerRegisterDeviceRemovalCallback(hidManagerRef,Handle_RemovalCallback, self);
+
+ // schedule us with the runloop
+ IOHIDManagerScheduleWithRunLoop(hidManagerRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+
+ IOReturn ioReturn = IOHIDManagerOpen(hidManagerRef, kIOHIDOptionsTypeNone);
+ if (noErr != ioReturn) {
+ if ([delegate respondsToSelector:@selector(onDeviceConnectionError:)]) {
+ [delegate onDeviceConnectionError:(long int)ioReturn];
+ }
+ //fprintf(stderr, "%s, IOHIDDeviceOpen error: %ld (0x%08lX ).\n", __PRETTY_FUNCTION__, (long int) ioReturn, (long int) ioReturn);
+ }
+ } else {
+ if ([delegate respondsToSelector:@selector(onDeviceConnectionError:)]) {
+ [delegate onDeviceConnectionError:3];
+ }
+ }
+
+}
+
+- (void)disconnect {
+ if (hidManagerRef) {
+ isConnected = NO;
+ IOReturn ioReturn = IOHIDManagerClose(hidManagerRef, kIOHIDOptionsTypeNone);
+ if (noErr != ioReturn) {
+ //fprintf(stderr, "%s, IOHIDManagerClose error: %ld (0x%08lX ).\n", __PRETTY_FUNCTION__, (long int) ioReturn, (long int) ioReturn);
+ }
+ CFRelease(hidManagerRef);
+ hidManagerRef = NULL;
+ if ([delegate respondsToSelector:@selector(onDeviceDisconnected)]) {
+ [delegate onDeviceDisconnected];
+ }
+ }
+}
+
+- (void) setDelegate:(id<PS3SixAxisDelegate>)aDelegate {
+ delegate = aDelegate;
+}
+
+- (id<PS3SixAxisDelegate>)delegate {
+ return delegate;
+}
+
+- (void)setUseBuffered:(BOOL)doUseBuffered {
+ useBuffered = isUseBuffered = doUseBuffered;
+}
+
+- (BOOL)useBuffered {
+ return useBuffered;
+}
+
+@end
259 PS3SixAxis/sixaxis.c
@@ -0,0 +1,259 @@
+#include "sixaxis.h"
+#include <string.h>
+#include <stdio.h>
+#include <arpa/inet.h> /* for htons */
+
+static int clamp(int min, int val, int max)
+{
+ if (val < min) return min;
+ if (val > max) return max;
+ return val;
+}
+
+void sixaxis_init(struct sixaxis_state *state)
+{
+ memset(state, 0, sizeof(struct sixaxis_state));
+
+ state->sys.reporting_enabled = 0;
+ state->sys.feature_ef_byte_6 = 0xa0;
+}
+
+int sixaxis_periodic_report(struct sixaxis_state *state)
+{
+ int ret;
+ ret = state->sys.reporting_enabled;
+ return ret;
+}
+
+const int digital_order[17] = {
+ sb_select, sb_l3, sb_r3, sb_start,
+ sb_up, sb_right, sb_down, sb_left,
+ sb_l2, sb_r2, sb_l1, sb_r1,
+ sb_triangle, sb_circle, sb_cross, sb_square,
+ sb_ps };
+
+const int analog_order[12] = {
+ sb_up, sb_right, sb_down, sb_left,
+ sb_l2, sb_r2, sb_l1, sb_r1,
+ sb_triangle, sb_circle, sb_cross, sb_square };
+
+/* Main input report from Sixaxis -- assemble it */
+int assemble_input_01(uint8_t *buf, int maxlen, struct sixaxis_state *state)
+{
+ struct sixaxis_state_user *u = &state->user;
+ int i;
+
+ if (maxlen < 48) return -1;
+ memset(buf, 0, 48);
+
+ /* Digital button state */
+ for (i = 0; i < 17; i++) {
+ int byte = 1 + (i / 8);
+ int offset = i % 8;
+ if (u->button[digital_order[i]].pressed)
+ buf[byte] |= (1 << offset);
+ }
+
+ /* Axes */
+ buf[5] = clamp(0, u->axis[0].x + 128, 255);
+ buf[6] = clamp(0, u->axis[0].y + 128, 255);
+ buf[7] = clamp(0, u->axis[1].x + 128, 255);
+ buf[8] = clamp(0, u->axis[1].y + 128, 255);
+
+ /* Analog button state */
+ for (i = 0; i < 12; i++)
+ buf[13 + i] = u->button[analog_order[i]].value;
+
+ /* Charging status? */
+ buf[28] = 0x03;
+
+ /* Power rating? */
+ buf[29] = 0x05;
+
+ /* Bluetooth and rumble status? */
+ buf[30] = 0x16;
+
+ /* Unknown, some values fluctuate? */
+ buf[31] = 0x00;
+ buf[32] = 0x00;
+ buf[33] = 0x00;
+ buf[34] = 0x00;
+ buf[35] = 0x33;
+ buf[36] = 0x02;
+ buf[37] = 0x77;
+ buf[38] = 0x01;
+ buf[39] = 0x9e;
+
+ /* Accelerometers */
+ *(uint16_t *)&buf[40] = htons(clamp(0, u->accel.x + 512, 1023));
+ *(uint16_t *)&buf[42] = htons(clamp(0, u->accel.y + 512, 1023));
+ *(uint16_t *)&buf[44] = htons(clamp(0, u->accel.z + 512, 1023));
+ *(uint16_t *)&buf[46] = htons(clamp(0, u->accel.gyro + 512, 1023));
+
+ return 48;
+}
+
+/* Main input report from Sixaxis -- decode it */
+int process_input_01(const uint8_t *buf, int len, struct sixaxis_state *state)
+{
+ struct sixaxis_state_user *u = &state->user;
+ int i;
+
+ if (len < 48) return -1;
+ /* Digital button state */
+ for (i = 0; i < 17; i++) {
+ int byte = 1 + (i / 8);
+ int offset = i % 8;
+ if (buf[byte] & (1 << offset))
+ u->button[digital_order[i]].pressed = 1;
+ else
+ u->button[digital_order[i]].pressed = 0;
+ }
+
+ /* Axes */
+ u->axis[0].x = buf[5] - 128;
+ u->axis[0].y = buf[6] - 128;
+ u->axis[1].x = buf[7] - 128;
+ u->axis[1].y = buf[8] - 128;
+
+ /* Analog button state */
+ for (i = 0; i < 12; i++)
+ u->button[analog_order[i]].value = buf[13 + i];
+
+ /* Accelerometers */
+ u->accel.x = ntohs(*(uint16_t *)&buf[40]) - 512;
+ u->accel.y = ntohs(*(uint16_t *)&buf[42]) - 512;
+ u->accel.z = ntohs(*(uint16_t *)&buf[44]) - 512;
+ u->accel.gyro = ntohs(*(uint16_t *)&buf[46]) - 512;
+
+ return 0;
+}
+
+/* Unknown */
+int assemble_feature_01(uint8_t *buf, int maxlen, struct sixaxis_state *state)
+{
+ const uint8_t data[] = {
+ 0x01, 0x03, 0x00, 0x05, 0x0c, 0x01, 0x02, 0x18,
+ 0x18, 0x18, 0x18, 0x09, 0x0a, 0x10, 0x11, 0x12,
+ 0x13, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02,
+ 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x04, 0x04,
+ 0x04, 0x04, 0x00, 0x00, 0x02, 0x01, 0x02, 0x00,
+ 0x64, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ int len = sizeof(data);
+ if (len > maxlen) return -1;
+ memcpy(buf, data, len);
+
+ return len;
+}
+
+/* Unknown */
+int assemble_feature_ef(uint8_t *buf, int maxlen, struct sixaxis_state *state)
+{
+ const uint8_t data[] = {
+ 0xef, 0x04, 0x00, 0x05, 0x03, 0x01, 0xb0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x74, 0x02, 0x71, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04
+ };
+ int len = sizeof(data);
+ if (len > maxlen) return -1;
+ memcpy(buf, data, len);
+
+ /* Byte 6 must match the byte set by the PS3 */
+ buf[6] = state->sys.feature_ef_byte_6;
+
+ return len;
+}
+
+/* Unknown */
+int assemble_feature_f2(uint8_t *buf, int maxlen, struct sixaxis_state *state)
+{
+ const uint8_t data[] = {
+ 0xff, 0xff, 0x00, 0x00, 0x1e, 0x3d, 0x24, 0x97,
+ 0xde, 0x00, 0x03, 0x50, 0x89, 0xc0, 0x01, 0x8a,
+ 0x09
+ };
+ int len = sizeof(data);
+ if (len > maxlen) return -1;
+ memcpy(buf, data, len);
+
+ return len;
+}
+
+/* Unknown */
+int assemble_feature_f8(uint8_t *buf, int maxlen, struct sixaxis_state *state)
+{
+ const uint8_t data[] = {
+ 0x01, 0x00, 0x00, 0x00
+ };
+ int len = sizeof(data);
+ if (len > maxlen) return -1;
+ memcpy(buf, data, len);
+
+ return len;
+}
+
+/* Main output report from PS3 including rumble and LEDs */
+int process_output_01(const uint8_t *buf, int len, struct sixaxis_state *state)
+{
+ int i;
+
+ if (len < 48)
+ return -1;
+
+ /* Decode LEDs. This ignores a lot of details of the LED bits */
+ for (i = 0; i < 5; i++) {
+ if (buf[9] & (1 << i)) {
+ if (buf[13 + 5 * i] == 0)
+ state->sys.led[i] = LED_ON;
+ else
+ state->sys.led[i] = LED_FLASH;
+ } else {
+ state->sys.led[i] = LED_OFF;
+ }
+ }
+
+ /* Decode rumble. Again, ignores some details */
+ state->sys.rumble[0] = buf[1] ? buf[2] : 0;
+ state->sys.rumble[1] = buf[3] ? buf[4] : 0;
+
+ return 0;
+}
+
+/* Unknown */
+int process_feature_ef(const uint8_t *buf, int len, struct sixaxis_state *state)
+{
+ if (len < 7)
+ return -1;
+ /* Need to remember byte 6 for assemble_feature_ef */
+ state->sys.feature_ef_byte_6 = buf[6];
+ return 0;
+}
+
+/* Enable reporting */
+int process_feature_f4(const uint8_t *buf, int len, struct sixaxis_state *state)
+{
+ /* Enable event reporting */
+ state->sys.reporting_enabled = 1;
+ return 0;
+}
+
+struct sixaxis_assemble_t sixaxis_assemble[] = {
+ { HID_TYPE_INPUT, 0x01, assemble_input_01 },
+ { HID_TYPE_FEATURE, 0x01, assemble_feature_01 },
+ { HID_TYPE_FEATURE, 0xef, assemble_feature_ef },
+ { HID_TYPE_FEATURE, 0xf2, assemble_feature_f2 },
+ { HID_TYPE_FEATURE, 0xf8, assemble_feature_f8 },
+ { 0 }
+};
+
+struct sixaxis_process_t sixaxis_process[] = {
+ { HID_TYPE_INPUT, 0x01, process_input_01 },
+ { HID_TYPE_OUTPUT, 0x01, process_output_01 },
+ { HID_TYPE_FEATURE, 0xef, process_feature_ef },
+ { HID_TYPE_FEATURE, 0xf4, process_feature_f4 },
+ { 0 }
+};
92 PS3SixAxis/sixaxis.h
@@ -0,0 +1,92 @@
+#ifndef SIXAXIS_H
+#define SIXAXIS_H
+
+#include <stdint.h>
+#include <stdbool.h>
+
+#define HID_HANDSHAKE 0x0
+#define HID_GET_REPORT 0x4
+#define HID_SET_REPORT 0x5
+#define HID_DATA 0xA
+
+#define HID_TYPE_RESERVED 0
+#define HID_TYPE_INPUT 1
+#define HID_TYPE_OUTPUT 2
+#define HID_TYPE_FEATURE 3
+
+struct sixaxis_button {
+ /* It's possible for a button to report as being pressed
+ but still have a zero value */
+ bool pressed;
+ /* 0 to 255 */
+ uint8_t value;
+};
+
+struct sixaxis_axis {
+ /* -128 to 127 */
+ int x;
+ int y;
+};
+
+struct sixaxis_accelerometer {
+ /* -512 to 511 */
+ int x;
+ int y;
+ int z;
+ int gyro;
+};
+
+enum sixaxis_button_index {
+ sb_select = 0, sb_start, sb_ps,
+ sb_up, sb_right, sb_down, sb_left,
+ sb_triangle, sb_circle, sb_cross, sb_square,
+ sb_l1, sb_r1,
+ sb_l2, sb_r2,
+ sb_l3, sb_r3,
+ SB_MAX
+};
+
+enum led_state_t { LED_OFF = 0, LED_FLASH, LED_ON };
+
+struct sixaxis_state_sys {
+ /*** Values provided by the system (PS3): */
+ int reporting_enabled;
+ int feature_ef_byte_6;
+
+ /* led[0] is the spare */
+ /* led[1]..led[4] correspond to printed text 1..4 */
+ enum led_state_t led[5];
+ uint8_t rumble[2];
+};
+
+struct sixaxis_state_user {
+ /*** Values provided by the user (controller): */
+ struct sixaxis_button button[SB_MAX];
+ struct sixaxis_axis axis[2];
+ struct sixaxis_accelerometer accel;
+};
+
+struct sixaxis_state {
+ struct sixaxis_state_sys sys;
+ struct sixaxis_state_user user;
+};
+
+struct sixaxis_assemble_t {
+ int type;
+ uint8_t report;
+ int (*func)(uint8_t *buf, int maxlen, struct sixaxis_state *state);
+};
+
+struct sixaxis_process_t {
+ int type;
+ uint8_t report;
+ int (*func)(const uint8_t *buf, int len, struct sixaxis_state *state);
+};
+
+extern struct sixaxis_assemble_t sixaxis_assemble[];
+extern struct sixaxis_process_t sixaxis_process[];
+
+void sixaxis_init(struct sixaxis_state *state);
+int sixaxis_periodic_report(struct sixaxis_state *state);
+
+#endif
28 PS3SixAxisTest-Info.plist
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.yourcompany.${PRODUCT_NAME:rfc1034identifier}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>${MACOSX_DEPLOYMENT_TARGET}</string>
+ <key>NSMainNibFile</key>
+ <string>PS3SixAxisTest</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+</dict>
+</plist>
6,286 PS3SixAxisTest.xib
6,286 additions, 0 deletions not shown because the diff is too large. Please use a local Git client to view these changes.
96 PS3SixAxisTest/PS3SixAxisTest.h
@@ -0,0 +1,96 @@
+//
+// PS3SixAxisTest.h
+// PS3SixAxis
+//
+// Created by Tobias Wetzel on 04.05.10.
+// Copyright 2010 Outcut. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+#import <PS3SixAxis.h>
+#import <SixAxisStick.h>
+
+@interface PS3SixAxisTest : NSObject <NSApplicationDelegate, PS3SixAxisDelegate> {
+ PS3SixAxis *ps3SixAxis;
+ NSButton *connectButton;
+ NSButton *disconnectButton;
+ NSButton *useBluetooth;
+ NSImageView *led;
+
+ NSButton *selectButton;
+ NSButton *startButton;
+ NSButton *psButton;
+
+ NSButton *triangleButton;
+ NSLevelIndicator *trianglePressure;
+ NSButton *circleButton;
+ NSLevelIndicator *circlePressure;
+ NSButton *crossButton;
+ NSLevelIndicator *crossPressure;
+ NSButton *squareButton;
+ NSLevelIndicator *squarePressure;
+
+ NSButton *l1Button;
+ NSLevelIndicator *l1Pressure;
+ NSButton *l2Button;
+ NSLevelIndicator *l2Pressure;
+ NSButton *r1Button;
+ NSLevelIndicator *r1Pressure;
+ NSButton *r2Button;
+ NSLevelIndicator *r2Pressure;
+
+ NSButton *northButton;
+ NSLevelIndicator *northPressure;
+ NSButton *eastButton;
+ NSLevelIndicator *eastPressure;
+ NSButton *southButton;
+ NSLevelIndicator *southPressure;
+ NSButton *westButton;
+ NSLevelIndicator *westPressure;
+
+ SixAxisStick *leftStick;
+ SixAxisStick *rightStick;
+}
+
+@property (assign) IBOutlet NSButton *connectButton;
+@property (assign) IBOutlet NSButton *disconnectButton;
+@property (assign) IBOutlet NSButton *useBluetooth;
+@property (assign) IBOutlet NSImageView *led;
+
+@property (assign) IBOutlet NSButton *selectButton;
+@property (assign) IBOutlet NSButton *startButton;
+@property (assign) IBOutlet NSButton *psButton;
+
+@property (assign) IBOutlet NSButton *triangleButton;
+@property (assign) IBOutlet NSLevelIndicator *trianglePressure;
+@property (assign) IBOutlet NSButton *circleButton;
+@property (assign) IBOutlet NSLevelIndicator *circlePressure;
+@property (assign) IBOutlet NSButton *squareButton;
+@property (assign) IBOutlet NSLevelIndicator *squarePressure;
+@property (assign) IBOutlet NSButton *crossButton;
+@property (assign) IBOutlet NSLevelIndicator *crossPressure;
+
+@property (assign) IBOutlet NSButton *l1Button;
+@property (assign) IBOutlet NSLevelIndicator *l1Pressure;
+@property (assign) IBOutlet NSButton *l2Button;
+@property (assign) IBOutlet NSLevelIndicator *l2Pressure;
+@property (assign) IBOutlet NSButton *r1Button;
+@property (assign) IBOutlet NSLevelIndicator *r1Pressure;
+@property (assign) IBOutlet NSButton *r2Button;
+@property (assign) IBOutlet NSLevelIndicator *r2Pressure;
+
+@property (assign) IBOutlet NSButton *northButton;
+@property (assign) IBOutlet NSLevelIndicator *northPressure;
+@property (assign) IBOutlet NSButton *eastButton;
+@property (assign) IBOutlet NSLevelIndicator *eastPressure;
+@property (assign) IBOutlet NSButton *southButton;
+@property (assign) IBOutlet NSLevelIndicator *southPressure;
+@property (assign) IBOutlet NSButton *westButton;
+@property (assign) IBOutlet NSLevelIndicator *westPressure;
+
+@property (assign) IBOutlet SixAxisStick *leftStick;
+@property (assign) IBOutlet SixAxisStick *rightStick;
+
+- (IBAction) doConnect:(id)sender;
+- (IBAction) doDisconnect:(id)sender;
+@end
193 PS3SixAxisTest/PS3SixAxisTest.m
@@ -0,0 +1,193 @@
+//
+// PS3SixAxisTest.m
+// PS3_SixAxis
+//
+// Created by Tobias Wetzel on 04.05.10.
+// Copyright 2010 Outcut. All rights reserved.
+//
+
+#import "PS3SixAxisTest.h"
+
+
+@implementation PS3SixAxisTest
+
+@synthesize connectButton, disconnectButton, useBluetooth;
+@synthesize led;
+
+@synthesize selectButton, startButton, psButton;
+
+@synthesize triangleButton, trianglePressure;
+@synthesize circleButton, circlePressure;
+@synthesize crossButton, crossPressure;
+@synthesize squareButton, squarePressure;
+
+@synthesize l1Button, l1Pressure;
+@synthesize l2Button, l2Pressure;
+@synthesize r1Button, r1Pressure;
+@synthesize r2Button, r2Pressure;
+
+@synthesize northButton, northPressure;
+@synthesize eastButton, eastPressure;
+@synthesize southButton, southPressure;
+@synthesize westButton, westPressure;
+
+@synthesize leftStick, rightStick;
+
+-(void)applicationDidFinishLaunching:(NSNotification *)aNotification {
+ ps3SixAxis = [PS3SixAxis sixAixisControllerWithDelegate:self];
+ [disconnectButton setEnabled:NO];
+}
+
+- (IBAction) doConnect:(id)sender {
+ [ps3SixAxis connect:[useBluetooth state]];
+}
+
+- (IBAction) doDisconnect:(id)sender {
+ [ps3SixAxis disconnect];
+}
+
+- (void) onDeviceConnected {
+ [connectButton setEnabled:NO];
+ [useBluetooth setEnabled:NO];
+ [disconnectButton setEnabled:YES];
+ [led setImage:[NSImage imageNamed:@"ledGreen"]];
+}
+
+- (void) onDeviceDisconnected {
+ [connectButton setEnabled:YES];
+ [useBluetooth setEnabled:YES];
+ [disconnectButton setEnabled:NO];
+ [led setImage:[NSImage imageNamed:@"ledRed"]];
+}
+
+- (void) onDeviceConnectionError:(NSInteger)error {
+ NSLog(@"%s %d", __PRETTY_FUNCTION__, error);
+ switch (error) {
+ case 0:
+ NSLog(@"");
+ break;
+ default:
+ break;
+ }
+}
+
+- (void) onAxisX:(int)x Y:(int)y Z:(int)z {
+ //NSLog(@"%s x:%d y:%d z:%d", __PRETTY_FUNCTION__, x, y, z);
+}
+
+- (void) onLeftStick:(NSPoint)axis pressed:(BOOL)isPressed {
+ [leftStick setJoyStickX:(int)axis.x Y:(int)axis.y pressed:isPressed];
+}
+
+- (void) onRightStick:(NSPoint)axis pressed:(BOOL)isPressed {
+ [rightStick setJoyStickX:(int)axis.x Y:(int)axis.y pressed:isPressed];
+}
+
+- (void) onTriangleButton:(BOOL)state {
+ [triangleButton highlight:state];
+}
+
+- (void) onTriangleButtonWithPressure:(NSInteger)value {
+ [trianglePressure setIntValue:value];
+}
+
+- (void) onCircleButton:(BOOL)state {
+ [circleButton highlight:state];
+}
+
+- (void) onCircleButtonWithPressure:(NSInteger)value {
+ [circlePressure setIntValue:value];
+}
+
+- (void) onCrossButton:(BOOL)state {
+ [crossButton highlight:state];
+}
+
+- (void) onCrossButtonWithPressure:(NSInteger)value {
+ [crossPressure setIntValue:value];
+}
+
+- (void) onSquareButton:(BOOL)state {
+ [squareButton highlight:state];
+}
+
+- (void) onSquareButtonWithPressure:(NSInteger)value {
+ [squarePressure setIntValue:value];
+}
+
+- (void) onL1Button:(BOOL)state {
+ [l1Button highlight:state];
+}
+
+- (void) onL2Button:(BOOL)state {
+ [l2Button highlight:state];
+}
+
+- (void) onR1Button:(BOOL)state {
+ [r1Button highlight:state];
+}
+
+- (void) onR2Button:(BOOL)state {
+ [r2Button highlight:state];
+}
+
+- (void) onL1ButtonWithPressure:(NSInteger)value {
+ [l1Pressure setIntValue:value];
+}
+
+- (void) onL2ButtonWithPressure:(NSInteger)value {
+ [l2Pressure setIntValue:value];
+}
+
+- (void) onR1ButtonWithPressure:(NSInteger)value {
+ [r1Pressure setIntValue:value];
+}
+
+- (void) onR2ButtonWithPressure:(NSInteger)value {
+ [r2Pressure setIntValue:value];
+}
+
+- (void) onSelectButton:(BOOL)state {
+ [selectButton highlight:state];
+}
+
+- (void) onStartButton:(BOOL)state {
+ [startButton highlight:state];
+}
+
+- (void) onPSButton:(BOOL)state {
+ [psButton highlight:state];
+}
+
+- (void) onNorthButton:(BOOL)state {
+ [northButton highlight:state];
+}
+- (void) onEastButton:(BOOL)state {
+ [eastButton highlight:state];
+}
+- (void) onSouthButton:(BOOL)state {
+ [southButton highlight:state];
+}
+- (void) onWestButton:(BOOL)state {
+ [westButton highlight:state];
+}
+
+- (void) onNorthButtonWithPressure:(NSInteger)value {
+ [northPressure setIntValue:value];
+}
+- (void) onEastButtonWithPressure:(NSInteger)value {
+ [eastPressure setIntValue:value];
+}
+- (void) onSouthButtonWithPressure:(NSInteger)value {
+ [southPressure setIntValue:value];
+}
+- (void) onWestButtonWithPressure:(NSInteger)value {
+ [westPressure setIntValue:value];
+}
+
+
+-(void)applicationWillTerminate:(NSNotification *)aNotification {
+ [ps3SixAxis disconnect];
+}
+
+@end
17 PS3SixAxisTest/SixAxisStick.h
@@ -0,0 +1,17 @@
+//
+// SixAxisStick.h
+// PS3_SixAxis
+//
+// Created by Tobias Wetzel on 11.05.10.
+// Copyright 2010 Outcut. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+#import <Quartz/Quartz.h>
+
+
+@interface SixAxisStick : NSView {
+ CALayer *point;
+}
+- (void) setJoyStickX:(NSInteger)x Y:(NSInteger)y pressed:(BOOL)isPressed;
+@end
47 PS3SixAxisTest/SixAxisStick.m
@@ -0,0 +1,47 @@
+//
+// SixAxisStick.m
+// PS3_SixAxis
+//
+// Created by Tobias Wetzel on 11.05.10.
+// Copyright 2010 Outcut. All rights reserved.
+//
+
+#import "SixAxisStick.h"
+
+
+@implementation SixAxisStick
+
+- (id) initWithFrame:(NSRect)frameRect {
+ if(self = [super initWithFrame:frameRect]) {
+ [self setWantsLayer:YES];
+
+ CGColorRef blackColor = CGColorCreateGenericRGB(0.0, 0.0, 0.0, 0.7);
+ CGColorRef whiteColor = CGColorCreateGenericRGB(1.0, 1.0, 1.0, 1.0);
+
+ point = [CALayer layer];
+ [point setAnchorPoint:CGPointMake(0, 0)];
+ [point setBounds:CGRectMake(0, 0, 20, 20)];
+ [point setShadowOpacity:.8f];
+ [point setCornerRadius:10];
+ [[self layer] setBackgroundColor:blackColor];
+ [[self layer] addSublayer:point];
+
+ [self setJoyStickX:128 Y:128 pressed:NO];
+ }
+ return self;
+}
+
+- (void) setJoyStickX:(NSInteger)x Y:(NSInteger)y pressed:(BOOL)isPressed {
+ NSSize size = [self frame].size;
+ float scale = size.width / (255 + 20);
+ CGColorRef pointColor;
+ if (isPressed) {
+ pointColor = CGColorCreateGenericRGB(1.0, 0.0, 0.0, 1.0);
+ } else {
+ pointColor = CGColorCreateGenericRGB(0.0, 0.0, 1.0, 1.0);
+ }
+ [point setBackgroundColor:pointColor];
+ [point setPosition:CGPointMake(x * scale - 10, size.height - (y * scale) - 10)];
+}
+
+@end
BIN PS3SixAxisTest/ledGreen.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN PS3SixAxisTest/ledRed.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN PS3SixAxisTest/logo.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 PS3SixAxisTest/main.m
@@ -0,0 +1,13 @@
+//
+// main.m
+// PS3_SixAxis
+//
+// Created by Tobias Wetzel on 04.05.10.
+// Copyright 2010 Outcut. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+
+int main(int argc, char*argv[]) {
+ return(NSApplicationMain(argc, (const char **) argv));
+}
693 PS3_SixAxis.xcodeproj/default.pbxuser
@@ -0,0 +1,693 @@
+// !$*UTF8*$!
+{
+ 089C165DFE840E0CC02AAC07 /* English */ = {
+ uiCtxt = {
+ sepNavIntBoundsRect = "{{0, 0}, {1621, 952}}";
+ sepNavSelRange = "{0, 0}";
+ sepNavVisRange = "{0, 94}";
+ sepNavWindowFrame = "{{15, -1}, {1680, 1024}}";
+ };
+ };
+ 29B97313FDCFA39411CA2CEA /* Project object */ = {
+ activeArchitecture = ppc;
+ activeBuildConfigurationName = Debug;
+ activeExecutable = 97EB1C250D2EF94200DF714C /* PS3_SixAxis */;
+ activeTarget = 8D1107260486CEB800E47090 /* PS3_SixAxis */;
+ addToTargets = (
+ 8D1107260486CEB800E47090 /* PS3_SixAxis */,
+ );
+ breakpoints = (
+ );
+ codeSenseManager = 97EB1C2E0D2EF94D00DF714C /* Code sense */;
+ executables = (
+ 97EB1C250D2EF94200DF714C /* PS3_SixAxis */,
+ );
+ perUserDictionary = {
+ PBXConfiguration.PBXFileTableDataSource3.PBXBookmarksDataSource = {
+ PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
+ PBXFileTableDataSourceColumnSortingKey = PBXBookmarksDataSource_NameID;
+ PBXFileTableDataSourceColumnWidthsKey = (
+ 200,
+ 200,
+ 982.58349609375,
+ );
+ PBXFileTableDataSourceColumnsKey = (
+ PBXBookmarksDataSource_LocationID,
+ PBXBookmarksDataSource_NameID,
+ PBXBookmarksDataSource_CommentsID,
+ );
+ };
+ PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = {
+ PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
+ PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
+ PBXFileTableDataSourceColumnWidthsKey = (
+ 20,
+ 1413,
+ 20,
+ 48,
+ 43,
+ 43,
+ 20,
+ );
+ PBXFileTableDataSourceColumnsKey = (
+ PBXFileDataSource_FiletypeID,
+ PBXFileDataSource_Filename_ColumnID,
+ PBXFileDataSource_Built_ColumnID,
+ PBXFileDataSource_ObjectSize_ColumnID,
+ PBXFileDataSource_Errors_ColumnID,
+ PBXFileDataSource_Warnings_ColumnID,
+ PBXFileDataSource_Target_ColumnID,
+ );
+ };
+ PBXConfiguration.PBXFileTableDataSource3.PBXFindDataSource = {
+ PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
+ PBXFileTableDataSourceColumnSortingKey = PBXFindDataSource_LocationID;
+ PBXFileTableDataSourceColumnWidthsKey = (
+ 200,
+ 1187,
+ );
+ PBXFileTableDataSourceColumnsKey = (
+ PBXFindDataSource_MessageID,
+ PBXFindDataSource_LocationID,
+ );
+ };
+ PBXConfiguration.PBXTargetDataSource.PBXTargetDataSource = {
+ PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
+ PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
+ PBXFileTableDataSourceColumnWidthsKey = (
+ 20,
+ 1133,
+ 60,
+ 20,
+ 48,
+ 43,
+ 43,
+ );
+ PBXFileTableDataSourceColumnsKey = (
+ PBXFileDataSource_FiletypeID,
+ PBXFileDataSource_Filename_ColumnID,
+ PBXTargetDataSource_PrimaryAttribute,
+ PBXFileDataSource_Built_ColumnID,
+ PBXFileDataSource_ObjectSize_ColumnID,
+ PBXFileDataSource_Errors_ColumnID,
+ PBXFileDataSource_Warnings_ColumnID,
+ );
+ };
+ PBXPerProjectTemplateStateSaveDate = 221770995;
+ PBXWorkspaceStateSaveDate = 221770995;
+ };
+ perUserProjectItems = {
+ 976A17800D37F67A000BF531 /* PBXTextBookmark */ = 976A17800D37F67A000BF531 /* PBXTextBookmark */;
+ 976A17850D37F67A000BF531 /* PBXTextBookmark */ = 976A17850D37F67A000BF531 /* PBXTextBookmark */;
+ 976A17870D37F67A000BF531 /* PBXTextBookmark */ = 976A17870D37F67A000BF531 /* PBXTextBookmark */;
+ 976A17880D37F67A000BF531 /* PBXTextBookmark */ = 976A17880D37F67A000BF531 /* PBXTextBookmark */;
+ 976A17890D37F67A000BF531 /* PBXTextBookmark */ = 976A17890D37F67A000BF531 /* PBXTextBookmark */;
+ 976A178A0D37F67A000BF531 /* PBXTextBookmark */ = 976A178A0D37F67A000BF531 /* PBXTextBookmark */;
+ 976A178B0D37F67A000BF531 /* PBXTextBookmark */ = 976A178B0D37F67A000BF531 /* PBXTextBookmark */;
+ 976A178C0D37F67A000BF531 /* PBXTextBookmark */ = 976A178C0D37F67A000BF531 /* PBXTextBookmark */;
+ 976A17A30D37F69C000BF531 /* PBXTextBookmark */ = 976A17A30D37F69C000BF531 /* PBXTextBookmark */;
+ 976A17A40D37F69C000BF531 /* PBXTextBookmark */ = 976A17A40D37F69C000BF531 /* PBXTextBookmark */;
+ 976A18B50D37F6FC000BF531 /* PBXTextBookmark */ = 976A18B50D37F6FC000BF531 /* PBXTextBookmark */;
+ 976A18B80D37F722000BF531 /* PBXBookmark */ = 976A18B80D37F722000BF531 /* PBXBookmark */;
+ 976A18BB0D37F76C000BF531 /* PBXTextBookmark */ = 976A18BB0D37F76C000BF531 /* PBXTextBookmark */;
+ 976A18BD0D37F76C000BF531 /* PBXTextBookmark */ = 976A18BD0D37F76C000BF531 /* PBXTextBookmark */;
+ 976A18BF0D37F7D5000BF531 /* PBXTextBookmark */ = 976A18BF0D37F7D5000BF531 /* PBXTextBookmark */;
+ 976A18C00D37F7D5000BF531 /* PBXTextBookmark */ = 976A18C00D37F7D5000BF531 /* PBXTextBookmark */;
+ 976A18C20D37F7D5000BF531 /* PBXTextBookmark */ = 976A18C20D37F7D5000BF531 /* PBXTextBookmark */;
+ 976A18C30D37F7D5000BF531 /* PBXTextBookmark */ = 976A18C30D37F7D5000BF531 /* PBXTextBookmark */;
+ 976A18C50D37F7D5000BF531 /* PBXTextBookmark */ = 976A18C50D37F7D5000BF531 /* PBXTextBookmark */;
+ 976A18C70D37F809000BF531 /* PBXTextBookmark */ = 976A18C70D37F809000BF531 /* PBXTextBookmark */;
+ 976A18C80D37F809000BF531 /* PBXTextBookmark */ = 976A18C80D37F809000BF531 /* PBXTextBookmark */;
+ 976A18C90D37F809000BF531 /* PBXTextBookmark */ = 976A18C90D37F809000BF531 /* PBXTextBookmark */;
+ 976A18CA0D37F809000BF531 /* PBXTextBookmark */ = 976A18CA0D37F809000BF531 /* PBXTextBookmark */;
+ 976A18CB0D37F809000BF531 /* PBXTextBookmark */ = 976A18CB0D37F809000BF531 /* PBXTextBookmark */;
+ 976A18CD0D37F818000BF531 /* PBXTextBookmark */ = 976A18CD0D37F818000BF531 /* PBXTextBookmark */;
+ 976A18CE0D37F818000BF531 /* PBXTextBookmark */ = 976A18CE0D37F818000BF531 /* PBXTextBookmark */;
+ 976A18D00D37F837000BF531 /* PBXTextBookmark */ = 976A18D00D37F837000BF531 /* PBXTextBookmark */;
+ 976A18D10D37F837000BF531 /* PBXTextBookmark */ = 976A18D10D37F837000BF531 /* PBXTextBookmark */;
+ 976A18D30D37F84A000BF531 /* PBXTextBookmark */ = 976A18D30D37F84A000BF531 /* PBXTextBookmark */;
+ 976A18D40D37F84A000BF531 /* PBXTextBookmark */ = 976A18D40D37F84A000BF531 /* PBXTextBookmark */;
+ 976A18D60D37F860000BF531 /* PBXTextBookmark */ = 976A18D60D37F860000BF531 /* PBXTextBookmark */;
+ 976A18D70D37F860000BF531 /* PBXTextBookmark */ = 976A18D70D37F860000BF531 /* PBXTextBookmark */;
+ 976A18E70D3818A4000BF531 /* PBXTextBookmark */ = 976A18E70D3818A4000BF531 /* PBXTextBookmark */;
+ 9770EDB60D36B83700659F63 = 9770EDB60D36B83700659F63 /* PBXTextBookmark */;
+ 9770EDB80D36B83700659F63 = 9770EDB80D36B83700659F63 /* PBXTextBookmark */;
+ 9770EDC10D36B8A500659F63 = 9770EDC10D36B8A500659F63 /* PBXTextBookmark */;
+ 9770EDC40D36B8A500659F63 = 9770EDC40D36B8A500659F63 /* PBXTextBookmark */;
+ 9770EDCF0D36B8F200659F63 = 9770EDCF0D36B8F200659F63 /* PBXTextBookmark */;
+ 9770EDD40D36B95000659F63 = 9770EDD40D36B95000659F63 /* PBXTextBookmark */;
+ 9770EDD70D36B95000659F63 = 9770EDD70D36B95000659F63 /* PBXTextBookmark */;
+ 9770EDE30D36BB6800659F63 = 9770EDE30D36BB6800659F63 /* PBXTextBookmark */;
+ 9770EDEB0D36C00500659F63 = 9770EDEB0D36C00500659F63 /* PBXTextBookmark */;
+ };
+ sourceControlManager = 97EB1C2D0D2EF94D00DF714C /* Source Control */;
+ userBuildSettings = {
+ };
+ };
+ 29B97316FDCFA39411CA2CEA /* main.m */ = {
+ uiCtxt = {
+ sepNavIntBoundsRect = "{{0, 0}, {1621, 1102}}";
+ sepNavSelRange = "{896, 0}";
+ sepNavVisRange = "{0, 904}";
+ sepNavWindowFrame = "{{15, 4}, {1680, 1174}}";
+ };
+ };
+ 32CA4F630368D1EE00C91783 /* PS3_SixAxis_Prefix.pch */ = {
+ uiCtxt = {
+ sepNavIntBoundsRect = "{{0, 0}, {1024, 1102}}";
+ sepNavSelRange = "{0, 0}";
+ sepNavVisRange = "{0, 153}";
+ sepNavWindowFrame = "{{15, -1}, {1083, 1174}}";
+ };
+ };
+ 8D1107260486CEB800E47090 /* PS3_SixAxis */ = {
+ activeExec = 0;
+ executables = (
+ 97EB1C250D2EF94200DF714C /* PS3_SixAxis */,
+ );
+ };
+ 8D1107310486CEB800E47090 /* Info.plist */ = {
+ uiCtxt = {
+ sepNavIntBoundsRect = "{{0, 0}, {1621, 1102}}";
+ sepNavSelRange = "{404, 0}";
+ sepNavVisRange = "{0, 838}";
+ sepNavWindowFrame = "{{15, -1}, {1680, 1174}}";
+ };
+ };
+ 97558E6C0D36879C00A702EF /* NSString.h */ = {
+ isa = PBXFileReference;
+ lastKnownFileType = sourcecode.c.h;
+ name = NSString.h;
+ path = /System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSString.h;
+ sourceTree = "<absolute>";
+ };
+ 976A17800D37F67A000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 97EB1C3B0D2F005A00DF714C /* SIOUX_Controller.m */;
+ name = "SIOUX_Controller.m: 30";
+ rLen = 0;
+ rLoc = 0;
+ rType = 0;
+ vrLen = 0;
+ vrLoc = 0;
+ };
+ 976A17850D37F67A000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 976A17860D37F67A000BF531 /* NSObject.h */;
+ name = "NSObject.h: 77";
+ rLen = 7;
+ rLoc = 1372;
+ rType = 0;
+ vrLen = 2108;
+ vrLoc = 0;
+ };
+ 976A17860D37F67A000BF531 /* NSObject.h */ = {
+ isa = PBXFileReference;
+ name = NSObject.h;
+ path = /System/Library/Frameworks/Foundation.framework/Versions/C/Headers/NSObject.h;
+ sourceTree = "<absolute>";
+ };
+ 976A17870D37F67A000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 97EB1C3A0D2F005A00DF714C /* SIOUX_Controller.h */;
+ name = "SIOUX_Controller.h: 17";
+ rLen = 0;
+ rLoc = 309;
+ rType = 0;
+ vrLen = 361;
+ vrLoc = 0;
+ };
+ 976A17880D37F67A000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 97EB1C3B0D2F005A00DF714C /* SIOUX_Controller.m */;
+ name = "SIOUX_Controller.m: 33";
+ rLen = 0;
+ rLoc = 0;
+ rType = 0;
+ vrLen = 1541;
+ vrLoc = 0;
+ };
+ 976A17890D37F67A000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 97EB1C3A0D2F005A00DF714C /* SIOUX_Controller.h */;
+ name = "SIOUX_Controller.h: 17";
+ rLen = 0;
+ rLoc = 309;
+ rType = 0;
+ vrLen = 361;
+ vrLoc = 0;
+ };
+ 976A178A0D37F67A000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 97EB1C3B0D2F005A00DF714C /* SIOUX_Controller.m */;
+ name = "SIOUX_Controller.m: 33";
+ rLen = 0;
+ rLoc = 0;
+ rType = 0;
+ vrLen = 1541;
+ vrLoc = 0;
+ };
+ 976A178B0D37F67A000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 97EB1C3A0D2F005A00DF714C /* SIOUX_Controller.h */;
+ name = "SIOUX_Controller.h: 17";
+ rLen = 0;
+ rLoc = 309;
+ rType = 0;
+ vrLen = 361;
+ vrLoc = 0;
+ };
+ 976A178C0D37F67A000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 97EB1C3B0D2F005A00DF714C /* SIOUX_Controller.m */;
+ name = "SIOUX_Controller.m: 33";
+ rLen = 0;
+ rLoc = 0;
+ rType = 0;
+ vrLen = 1552;
+ vrLoc = 0;
+ };
+ 976A17A30D37F69C000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 97EB1C3B0D2F005A00DF714C /* SIOUX_Controller.m */;
+ rLen = 0;
+ rLoc = 78;
+ rType = 1;
+ };
+ 976A17A40D37F69C000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 97EB1C3B0D2F005A00DF714C /* SIOUX_Controller.m */;
+ name = "SIOUX_Controller.m: 20";
+ rLen = 0;
+ rLoc = 0;
+ rType = 0;
+ vrLen = 815;
+ vrLoc = 385;
+ };
+ 976A18B50D37F6FC000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 9770EDC20D36B8A500659F63 /* NSText.h */;
+ name = "NSText.h: 81";
+ rLen = 43;
+ rLoc = 3133;
+ rType = 0;
+ vrLen = 0;
+ vrLoc = 0;
+ };
+ 976A18B80D37F722000BF531 /* PBXBookmark */ = {
+ isa = PBXBookmark;
+ fRef = 97EB1C3B0D2F005A00DF714C /* SIOUX_Controller.m */;
+ };
+ 976A18BB0D37F76C000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 9770EDC20D36B8A500659F63 /* NSText.h */;
+ name = "NSText.h: 81";
+ rLen = 43;
+ rLoc = 3133;
+ rType = 0;
+ vrLen = 0;
+ vrLoc = 0;
+ };
+ 976A18BD0D37F76C000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 97EB1C3B0D2F005A00DF714C /* SIOUX_Controller.m */;
+ name = "SIOUX_Controller.m: 23";
+ rLen = 0;
+ rLoc = 0;
+ rType = 0;
+ vrLen = 1765;
+ vrLoc = 0;
+ };
+ 976A18BF0D37F7D5000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 9770EDC20D36B8A500659F63 /* NSText.h */;
+ name = "NSText.h: 81";
+ rLen = 43;
+ rLoc = 3133;
+ rType = 0;
+ vrLen = 0;
+ vrLoc = 0;
+ };
+ 976A18C00D37F7D5000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 976A18C10D37F7D5000BF531 /* NSWindow.h */;
+ name = "NSWindow.h: 357";
+ rLen = 20;
+ rLoc = 13613;
+ rType = 0;
+ vrLen = 3112;
+ vrLoc = 11222;
+ };
+ 976A18C10D37F7D5000BF531 /* NSWindow.h */ = {
+ isa = PBXFileReference;
+ lastKnownFileType = sourcecode.c.h;
+ name = NSWindow.h;
+ path = /System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSWindow.h;
+ sourceTree = "<absolute>";
+ uiCtxt = {
+ sepNavIntBoundsRect = "{{0, 0}, {4676, 7678}}";
+ sepNavSelRange = "{13613, 20}";
+ sepNavVisRange = "{2622, 3365}";
+ };
+ };
+ 976A18C20D37F7D5000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 97EB1C3B0D2F005A00DF714C /* SIOUX_Controller.m */;
+ name = "SIOUX_Controller.m: 76";
+ rLen = 10;
+ rLoc = 1942;
+ rType = 0;
+ vrLen = 1869;
+ vrLoc = 0;
+ };
+ 976A18C30D37F7D5000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 976A18C40D37F7D5000BF531 /* NSWindow.h */;
+ name = "NSWindow.h: 357";
+ rLen = 20;
+ rLoc = 13613;
+ rType = 0;
+ vrLen = 3112;
+ vrLoc = 11222;
+ };
+ 976A18C40D37F7D5000BF531 /* NSWindow.h */ = {
+ isa = PBXFileReference;
+ name = NSWindow.h;
+ path = /System/Library/Frameworks/AppKit.framework/Versions/C/Headers/NSWindow.h;
+ sourceTree = "<absolute>";
+ };
+ 976A18C50D37F7D5000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 97EB1C3B0D2F005A00DF714C /* SIOUX_Controller.m */;
+ name = "SIOUX_Controller.m: 78";
+ rLen = 0;
+ rLoc = 2000;
+ rType = 0;
+ vrLen = 1915;
+ vrLoc = 0;
+ };
+ 976A18C70D37F809000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 9770EDC20D36B8A500659F63 /* NSText.h */;
+ name = "NSText.h: 81";
+ rLen = 43;
+ rLoc = 3133;
+ rType = 0;
+ vrLen = 0;
+ vrLoc = 0;
+ };
+ 976A18C80D37F809000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 976A18C10D37F7D5000BF531 /* NSWindow.h */;
+ name = "NSWindow.h: 357";
+ rLen = 20;
+ rLoc = 13613;
+ rType = 0;
+ vrLen = 3365;
+ vrLoc = 2622;
+ };
+ 976A18C90D37F809000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 97EB1C3B0D2F005A00DF714C /* SIOUX_Controller.m */;
+ name = "SIOUX_Controller.m: 77";
+ rLen = 20;
+ rLoc = 1977;
+ rType = 0;
+ vrLen = 1913;
+ vrLoc = 0;
+ };
+ 976A18CA0D37F809000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 976A18C10D37F7D5000BF531 /* NSWindow.h */;
+ name = "NSWindow.h: 357";
+ rLen = 20;
+ rLoc = 13613;
+ rType = 0;
+ vrLen = 3365;
+ vrLoc = 2622;
+ };
+ 976A18CB0D37F809000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 97EB1C3B0D2F005A00DF714C /* SIOUX_Controller.m */;
+ name = "SIOUX_Controller.m: 76";
+ rLen = 0;
+ rLoc = 1927;
+ rType = 0;
+ vrLen = 1911;
+ vrLoc = 0;
+ };
+ 976A18CD0D37F818000BF531 /* PBXTextBookmark */ = {
+ isa = PBXTextBookmark;
+ fRef = 9770EDC20D36B8A500659F63 /* NSText.h */;
+ name = "NSText.h: 81";
+ rLen = 43;
+ rLoc = 3133;