diff --git a/360Controller/360Controller.xcodeproj/project.pbxproj b/360Controller/360Controller.xcodeproj/project.pbxproj new file mode 100644 index 00000000..04a14efa --- /dev/null +++ b/360Controller/360Controller.xcodeproj/project.pbxproj @@ -0,0 +1,390 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 32D94FC60562CBF700B6AF17 /* _60Controller.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A224C3EFF42367911CA2CB7 /* _60Controller.h */; }; + 32D94FC80562CBF700B6AF17 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C167DFE841241C02AAC07 /* InfoPlist.strings */; }; + 32D94FCA0562CBF700B6AF17 /* _60Controller.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A224C3FFF42367911CA2CB7 /* _60Controller.cpp */; settings = {ATTRIBUTES = (); }; }; + 3B36DCC410B7816F00FFD769 /* Controller.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3B36DCC210B7816F00FFD769 /* Controller.cpp */; }; + 3B36DCC510B7816F00FFD769 /* Controller.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B36DCC310B7816F00FFD769 /* Controller.h */; }; + 3B36DCCB10B7817E00FFD769 /* ChatPad.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3B36DCC610B7817E00FFD769 /* ChatPad.cpp */; }; + 3B36DCCC10B7817E00FFD769 /* ChatPad.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B36DCC710B7817E00FFD769 /* ChatPad.h */; }; + 3B36DCCD10B7817E00FFD769 /* chatpadhid.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B36DCC810B7817E00FFD769 /* chatpadhid.h */; }; + 3B36DCCE10B7817E00FFD769 /* chatpadkeys.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3B36DCC910B7817E00FFD769 /* chatpadkeys.cpp */; }; + 3B36DCCF10B7817E00FFD769 /* chatpadkeys.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B36DCCA10B7817E00FFD769 /* chatpadkeys.h */; }; + 3BB5E09C09641F8200F83598 /* xbox360hid.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BB5E09B09641F8200F83598 /* xbox360hid.h */; }; + 3BCE45CA09638EBC00B69EDF /* ControlStruct.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BCE45C909638EBC00B69EDF /* ControlStruct.h */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 089C167EFE841241C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + 1A224C3EFF42367911CA2CB7 /* _60Controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = _60Controller.h; sourceTree = ""; }; + 1A224C3FFF42367911CA2CB7 /* _60Controller.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = _60Controller.cpp; sourceTree = ""; }; + 32D94FCF0562CBF700B6AF17 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 32D94FD00562CBF700B6AF17 /* 360Controller.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = 360Controller.kext; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B0F1276097B395B00127827 /* Feedback360.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = Feedback360.bundle; path = ../Feedback360/build/Deployment/Feedback360.bundle; sourceTree = SOURCE_ROOT; }; + 3B36DCC210B7816F00FFD769 /* Controller.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Controller.cpp; sourceTree = ""; }; + 3B36DCC310B7816F00FFD769 /* Controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Controller.h; sourceTree = ""; }; + 3B36DCC610B7817E00FFD769 /* ChatPad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ChatPad.cpp; sourceTree = ""; }; + 3B36DCC710B7817E00FFD769 /* ChatPad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChatPad.h; sourceTree = ""; }; + 3B36DCC810B7817E00FFD769 /* chatpadhid.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = chatpadhid.h; sourceTree = ""; }; + 3B36DCC910B7817E00FFD769 /* chatpadkeys.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = chatpadkeys.cpp; sourceTree = ""; }; + 3B36DCCA10B7817E00FFD769 /* chatpadkeys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = chatpadkeys.h; sourceTree = ""; }; + 3BB5E09B09641F8200F83598 /* xbox360hid.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = xbox360hid.h; sourceTree = ""; }; + 3BCE45C909638EBC00B69EDF /* ControlStruct.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ControlStruct.h; sourceTree = ""; }; + 8DA8362C06AD9B9200E5AC22 /* Kernel.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Kernel.framework; path = /System/Library/Frameworks/Kernel.framework; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 32D94FCB0562CBF700B6AF17 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 089C166AFE841209C02AAC07 /* 360Controller */ = { + isa = PBXGroup; + children = ( + 247142CAFF3F8F9811CA285C /* Source */, + 089C167CFE841241C02AAC07 /* Resources */, + 19C28FB6FE9D52B211CA2CBB /* Products */, + ); + name = 360Controller; + sourceTree = ""; + }; + 089C167CFE841241C02AAC07 /* Resources */ = { + isa = PBXGroup; + children = ( + 3B2EF52A0965A0AE007BFB7B /* Kernel Driver */, + ); + name = Resources; + sourceTree = ""; + }; + 19C28FB6FE9D52B211CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 32D94FD00562CBF700B6AF17 /* 360Controller.kext */, + ); + name = Products; + sourceTree = ""; + }; + 247142CAFF3F8F9811CA285C /* Source */ = { + isa = PBXGroup; + children = ( + 3B2EF19A0965A03E007BFB7B /* Kernel Driver */, + ); + name = Source; + sourceTree = ""; + }; + 3B2EF19A0965A03E007BFB7B /* Kernel Driver */ = { + isa = PBXGroup; + children = ( + 3B36DCC010B7815000FFD769 /* Controller */, + 3B36DCC110B7815700FFD769 /* ChatPad */, + 3BCE45C909638EBC00B69EDF /* ControlStruct.h */, + 1A224C3EFF42367911CA2CB7 /* _60Controller.h */, + 1A224C3FFF42367911CA2CB7 /* _60Controller.cpp */, + ); + name = "Kernel Driver"; + sourceTree = ""; + }; + 3B2EF52A0965A0AE007BFB7B /* Kernel Driver */ = { + isa = PBXGroup; + children = ( + 3B0F1276097B395B00127827 /* Feedback360.bundle */, + 8DA8362C06AD9B9200E5AC22 /* Kernel.framework */, + 32D94FCF0562CBF700B6AF17 /* Info.plist */, + 089C167DFE841241C02AAC07 /* InfoPlist.strings */, + ); + name = "Kernel Driver"; + sourceTree = ""; + }; + 3B36DCC010B7815000FFD769 /* Controller */ = { + isa = PBXGroup; + children = ( + 3B36DCC210B7816F00FFD769 /* Controller.cpp */, + 3B36DCC310B7816F00FFD769 /* Controller.h */, + 3BB5E09B09641F8200F83598 /* xbox360hid.h */, + ); + name = Controller; + sourceTree = ""; + }; + 3B36DCC110B7815700FFD769 /* ChatPad */ = { + isa = PBXGroup; + children = ( + 3B36DCC610B7817E00FFD769 /* ChatPad.cpp */, + 3B36DCC710B7817E00FFD769 /* ChatPad.h */, + 3B36DCC910B7817E00FFD769 /* chatpadkeys.cpp */, + 3B36DCCA10B7817E00FFD769 /* chatpadkeys.h */, + 3B36DCC810B7817E00FFD769 /* chatpadhid.h */, + ); + name = ChatPad; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 32D94FC50562CBF700B6AF17 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 32D94FC60562CBF700B6AF17 /* _60Controller.h in Headers */, + 3BCE45CA09638EBC00B69EDF /* ControlStruct.h in Headers */, + 3BB5E09C09641F8200F83598 /* xbox360hid.h in Headers */, + 3B36DCC510B7816F00FFD769 /* Controller.h in Headers */, + 3B36DCCC10B7817E00FFD769 /* ChatPad.h in Headers */, + 3B36DCCD10B7817E00FFD769 /* chatpadhid.h in Headers */, + 3B36DCCF10B7817E00FFD769 /* chatpadkeys.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 32D94FC30562CBF700B6AF17 /* 360Controller */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3BBDC682097938A90023AAD8 /* Build configuration list for PBXNativeTarget "360Controller" */; + buildPhases = ( + 32D94FC50562CBF700B6AF17 /* Headers */, + 32D94FC70562CBF700B6AF17 /* Resources */, + 32D94FC90562CBF700B6AF17 /* Sources */, + 32D94FCB0562CBF700B6AF17 /* Frameworks */, + 32D94FCC0562CBF700B6AF17 /* Rez */, + 3B0F12A1097B3A3A00127827 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 360Controller; + productInstallPath = "$(SYSTEM_LIBRARY_DIR)/Extensions"; + productName = 360Controller; + productReference = 32D94FD00562CBF700B6AF17 /* 360Controller.kext */; + productType = "com.apple.product-type.kernel-extension.iokit"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 089C1669FE841209C02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 3BBDC686097938A90023AAD8 /* Build configuration list for PBXProject "360Controller" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 089C166AFE841209C02AAC07 /* 360Controller */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 32D94FC30562CBF700B6AF17 /* 360Controller */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 32D94FC70562CBF700B6AF17 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 32D94FC80562CBF700B6AF17 /* InfoPlist.strings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXRezBuildPhase section */ + 32D94FCC0562CBF700B6AF17 /* Rez */ = { + isa = PBXRezBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXRezBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B0F12A1097B3A3A00127827 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "cd \"$TARGET_BUILD_DIR/$TARGET_NAME.kext/Contents\"\nmkdir PlugIns > /dev/null 2>&1\nrm -R PlugIns/Feedback360.plugin > /dev/null 2>&1\necho \"$SRCROOT/../Feedback360/build/Deployment/Feedback360.bundle\"\ncp -R \"$SRCROOT/../Feedback360/build/Deployment/Feedback360.bundle\" PlugIns/Feedback360.plugin\n# Renaming extension from bundle to a plugin? Could be naughty."; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 32D94FC90562CBF700B6AF17 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 32D94FCA0562CBF700B6AF17 /* _60Controller.cpp in Sources */, + 3B36DCC410B7816F00FFD769 /* Controller.cpp in Sources */, + 3B36DCCB10B7817E00FFD769 /* ChatPad.cpp in Sources */, + 3B36DCCE10B7817E00FFD769 /* chatpadkeys.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 089C167DFE841241C02AAC07 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 089C167EFE841241C02AAC07 /* English */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 3BBDC683097938A90023AAD8 /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1.0.0d12; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Extensions"; + MODULE_NAME = com.mice.driver.Xbox360Controller; + MODULE_VERSION = 1.0.0d11; + PREBINDING = NO; + PRODUCT_NAME = 360Controller; + SDKROOT = ""; + WRAPPER_EXTENSION = kext; + ZERO_LINK = YES; + }; + name = Development; + }; + 3BBDC684097938A90023AAD8 /* Deployment */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = ( + ppc, + i386, + x86_64, + ); + COPY_PHASE_STRIP = YES; + CURRENT_PROJECT_VERSION = 1.0.0d12; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_MODEL_TUNING = G5; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Extensions"; + LD_GENERATE_MAP_FILE = NO; + MODULE_NAME = com.mice.driver.Xbox360Controller; + MODULE_VERSION = 1.0.0d11; + PREBINDING = NO; + PRODUCT_NAME = 360Controller; + WRAPPER_EXTENSION = kext; + ZERO_LINK = NO; + }; + name = Deployment; + }; + 3BBDC685097938A90023AAD8 /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + CURRENT_PROJECT_VERSION = 1.0.0d12; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_MODEL_TUNING = G5; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Extensions"; + MODULE_NAME = com.mice.driver.Xbox360Controller; + MODULE_VERSION = 1.0.0d11; + PREBINDING = NO; + PRODUCT_NAME = 360Controller; + WRAPPER_EXTENSION = kext; + }; + name = Default; + }; + 3BBDC687097938A90023AAD8 /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "Developer ID Application: Colin Munro"; + MACOSX_DEPLOYMENT_TARGET = 10.5; + PROVISIONING_PROFILE = ""; + SDKROOT = ""; + }; + name = Development; + }; + 3BBDC688097938A90023AAD8 /* Deployment */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + CODE_SIGN_IDENTITY = "Developer ID Application: Colin Munro"; + GCC_VERSION = ""; + MACOSX_DEPLOYMENT_TARGET = 10.5; + PROVISIONING_PROFILE = ""; + SDKROOT = ""; + "SDKROOT[arch=x86_64]" = ""; + }; + name = Deployment; + }; + 3BBDC689097938A90023AAD8 /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "Developer ID Application: Colin Munro"; + MACOSX_DEPLOYMENT_TARGET = 10.5; + PROVISIONING_PROFILE = ""; + SDKROOT = ""; + }; + name = Default; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 3BBDC682097938A90023AAD8 /* Build configuration list for PBXNativeTarget "360Controller" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3BBDC683097938A90023AAD8 /* Development */, + 3BBDC684097938A90023AAD8 /* Deployment */, + 3BBDC685097938A90023AAD8 /* Default */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Default; + }; + 3BBDC686097938A90023AAD8 /* Build configuration list for PBXProject "360Controller" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3BBDC687097938A90023AAD8 /* Development */, + 3BBDC688097938A90023AAD8 /* Deployment */, + 3BBDC689097938A90023AAD8 /* Default */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Default; + }; +/* End XCConfigurationList section */ + }; + rootObject = 089C1669FE841209C02AAC07 /* Project object */; +} diff --git a/360Controller/ChatPad.cpp b/360Controller/ChatPad.cpp new file mode 100644 index 00000000..7b8feee8 --- /dev/null +++ b/360Controller/ChatPad.cpp @@ -0,0 +1,150 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + ChatPad.cpp - Implementation of the ChatPad Accessory driver + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include "ChatPad.h" +namespace HID_ChatPad { +#include "chatpadhid.h" +} +#include "chatpadkeys.h" +#include "_60Controller.h" + +OSDefineMetaClassAndStructors(ChatPadKeyboardClass, IOHIDDevice) + +IOReturn ChatPadKeyboardClass::newReportDescriptor(IOMemoryDescriptor **descriptor) const +{ + IOBufferMemoryDescriptor *buffer; + + buffer = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, 0, sizeof(HID_ChatPad::ReportDescriptor)); + if (buffer == NULL) + return kIOReturnNoResources; + buffer->writeBytes(0, HID_ChatPad::ReportDescriptor, sizeof(HID_ChatPad::ReportDescriptor)); + *descriptor = buffer; + return kIOReturnSuccess; +} + +IOReturn ChatPadKeyboardClass::setReport(IOMemoryDescriptor *report, IOHIDReportType reportType, IOOptionBits options) +{ + // Maybe add LED support later? + return kIOReturnUnsupported; +} + +IOReturn ChatPadKeyboardClass::getReport(IOMemoryDescriptor *report, IOHIDReportType reportType, IOOptionBits options) +{ + return kIOReturnUnsupported; +} + +IOReturn ChatPadKeyboardClass::handleReport(IOMemoryDescriptor *report, IOHIDReportType reportType, IOOptionBits options) +{ + IOBufferMemoryDescriptor *realReport = OSDynamicCast(IOBufferMemoryDescriptor, report); + if (realReport != NULL) + { + unsigned char *data = (unsigned char*)realReport->getBytesNoCopy(); + if (data[0] == 0x00) + { + for (int i = 2; i < 5; i++) + { + data[i] = ChatPad2USB(data[i]); + } + } + } + return IOHIDDevice::handleReport(report, reportType, options); +} + +OSNumber* ChatPadKeyboardClass::newPrimaryUsageNumber() const +{ + return OSNumber::withNumber(HID_ChatPad::ReportDescriptor[3], 8); +} + +OSNumber* ChatPadKeyboardClass::newPrimaryUsagePageNumber() const +{ + return OSNumber::withNumber(HID_ChatPad::ReportDescriptor[1], 8); +} + +OSString* ChatPadKeyboardClass::newProductString() const +{ + return OSString::withCString("ChatPad"); +} + +OSString* ChatPadKeyboardClass::newTransportString() const +{ + return OSString::withCString("Serial"); +} + +OSNumber* ChatPadKeyboardClass::newVendorIDNumber() const +{ + // Same as USB + return OSNumber::withNumber(100, 32); +} + +OSNumber* ChatPadKeyboardClass::newProductIDNumber() const +{ + // Same as USB, plus one + return OSNumber::withNumber(100, 32); +} + +static IOHIDDevice* GetParent(const IOService *current) +{ + Xbox360Peripheral *owner; + + owner = OSDynamicCast(Xbox360Peripheral, current->getProvider()); + if (owner == NULL) + return NULL; + return owner->getController(0); +} + +bool ChatPadKeyboardClass::start(IOService *provider) +{ + if (!IOHIDDevice::start(provider)) + return false; + return OSDynamicCast(Xbox360Peripheral, provider) != NULL; +} + +OSString* ChatPadKeyboardClass::newManufacturerString() const +{ + IOHIDDevice *device = GetParent(this); + if (device == NULL) + return NULL; + return device->newManufacturerString(); +} + +OSString* ChatPadKeyboardClass::newSerialNumberString() const +{ + IOHIDDevice *device = GetParent(this); + if (device == NULL) + return NULL; + return device->newSerialNumberString(); +} + +OSNumber* ChatPadKeyboardClass::newLocationIDNumber() const +{ + IOHIDDevice *device = GetParent(this); + if (device == NULL) + return NULL; + OSNumber *number = device->newLocationIDNumber(); + if (number == NULL) + return NULL; + UInt32 value = number->unsigned32BitValue(); + number->release(); + return OSNumber::withNumber(value + 1, 32); +} diff --git a/360Controller/ChatPad.h b/360Controller/ChatPad.h new file mode 100644 index 00000000..c7afdfaf --- /dev/null +++ b/360Controller/ChatPad.h @@ -0,0 +1,53 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + ChatPad.h - Driver class for the ChatPad accessory + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +class ChatPadKeyboardClass : public IOHIDDevice +{ + OSDeclareDefaultStructors(ChatPadKeyboardClass) + +private: + +public: + virtual bool start(IOService *provider); + + // IOHidDevice methods + virtual IOReturn newReportDescriptor(IOMemoryDescriptor **descriptor) const; + + virtual IOReturn setReport(IOMemoryDescriptor *report,IOHIDReportType reportType,IOOptionBits options=0); + virtual IOReturn getReport(IOMemoryDescriptor *report,IOHIDReportType reportType,IOOptionBits options); + + virtual IOReturn handleReport(IOMemoryDescriptor *report, IOHIDReportType reportType = kIOHIDReportTypeInput, IOOptionBits options = 0); + + virtual OSString* newManufacturerString() const; + virtual OSNumber* newPrimaryUsageNumber() const; + virtual OSNumber* newPrimaryUsagePageNumber() const; + virtual OSNumber* newProductIDNumber() const; + virtual OSString* newProductString() const; + virtual OSString* newSerialNumberString() const; + virtual OSString* newTransportString() const; + virtual OSNumber* newVendorIDNumber() const; + + virtual OSNumber* newLocationIDNumber() const; +}; diff --git a/360Controller/ControlStruct.h b/360Controller/ControlStruct.h new file mode 100644 index 00000000..80c5a651 --- /dev/null +++ b/360Controller/ControlStruct.h @@ -0,0 +1,115 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + ControlStruct.h - Structures used by the device + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef __CONTROLSTRUCT_H__ +#define __CONTROLSTRUCT_H__ + +typedef UInt8 XBox360_Byte; +typedef UInt16 XBox360_Short; +typedef SInt16 XBox360_SShort; + +#define Xbox360_Prepare(x,t) {memset(&x,0,sizeof(x));x.header.command=t;x.header.size=sizeof(x);} + +#define PACKED __attribute__((__packed__)) + +// Common structure format +typedef struct { + XBox360_Byte command; + XBox360_Byte size; +} PACKED XBOX360_PACKET; + +// Analog stick format +typedef struct { + XBox360_SShort x,y; +} PACKED XBOX360_HAT; + +// Structure describing the report had back from the controller +typedef struct { + XBOX360_PACKET header; + XBox360_Short buttons; + XBox360_Byte trigL,trigR; + XBOX360_HAT left,right; + XBox360_Byte reserved[6]; +} PACKED XBOX360_IN_REPORT; + +// Structure describing the command to change LED status +typedef struct { + XBOX360_PACKET header; + XBox360_Byte pattern; +} PACKED XBOX360_OUT_LED; + +// Structure describing the command to change rumble motor status +typedef struct { + XBOX360_PACKET header; + XBox360_Byte reserved1; + XBox360_Byte big,little; + XBox360_Byte reserved[3]; +} PACKED XBOX360_OUT_RUMBLE; + +// Enumeration of command types +enum { + // In + inReport = 0, + // Out + outRumble = 0, + outLed = 1 +}; + +// Button bits +enum { + btnHatRight = 0x8000, + btnHatLeft = 0x4000, + btnBack = 0x2000, + btnStart = 0x1000, + btnDigiRight = 0x0800, + btnDigiLeft = 0x0400, + btnDigiDown = 0x0200, + btnDigiUp = 0x0100, + btnY = 0x0080, + btnX = 0x0040, + btnB = 0x0020, + btnA = 0x0010, + btnReserved1 = 0x0008, // Unused? + btnXbox = 0x0004, + btnShoulderRight = 0x0002, + btnShoulderLeft = 0x0001 +}; + +// LED values +enum { + ledOff = 0x00, + ledBlinkingAll = 0x01, + ledFlashOn1 = 0x02, + ledFlashOn2 = 0x03, + ledFlashOn3 = 0x04, + ledFlashOn4 = 0x05, + ledOn1 = 0x06, + ledOn2 = 0x07, + ledOn3 = 0x08, + ledOn4 = 0x09, + ledRotating = 0x0a, + ledBlinking = 0x0b, // Blinking of previously enabled LED (e.g. from 0x01-0x09) + ledBlinkingSlow = 0x0c, // As above + ldAlternating = 0x0d // 1+4, 2+3, then back to previous after a short time +}; + +#endif // __CONTROLSTRUCT_H__ diff --git a/360Controller/Controller.cpp b/360Controller/Controller.cpp new file mode 100644 index 00000000..7bc3903e --- /dev/null +++ b/360Controller/Controller.cpp @@ -0,0 +1,211 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + Controller.cpp - driver class for the 360 controller + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include "Controller.h" +#include "ControlStruct.h" +namespace HID_360 { +#include "xbox360hid.h" +} +#include "_60Controller.h" + +OSDefineMetaClassAndStructors(Xbox360ControllerClass, IOHIDDevice) + +static Xbox360Peripheral* GetOwner(IOService *us) +{ + IOService *prov; + + prov = us->getProvider(); + if (prov == NULL) + return NULL; + return OSDynamicCast(Xbox360Peripheral, prov); +} + +static IOUSBDevice* GetOwnerProvider(const IOService *us) +{ + IOService *prov, *provprov; + + prov = us->getProvider(); + if (prov == NULL) + return NULL; + provprov = prov->getProvider(); + if (provprov == NULL) + return NULL; + return OSDynamicCast(IOUSBDevice, provprov); +} + +bool Xbox360ControllerClass::start(IOService *provider) +{ + if (OSDynamicCast(Xbox360Peripheral, provider) == NULL) + return false; + return IOHIDDevice::start(provider); +} + +IOReturn Xbox360ControllerClass::setProperties(OSObject *properties) +{ + Xbox360Peripheral *owner = GetOwner(this); + if (owner == NULL) + return kIOReturnUnsupported; + return owner->setProperties(properties); +} + +// Returns the HID descriptor for this device +IOReturn Xbox360ControllerClass::newReportDescriptor(IOMemoryDescriptor **descriptor) const +{ + IOBufferMemoryDescriptor *buffer; + + buffer=IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task,0,sizeof(HID_360::ReportDescriptor)); + if(buffer==NULL) return kIOReturnNoResources; + buffer->writeBytes(0,HID_360::ReportDescriptor,sizeof(HID_360::ReportDescriptor)); + *descriptor=buffer; + return kIOReturnSuccess; +} + +// Handles a message from the userspace IOHIDDeviceInterface122::setReport function +IOReturn Xbox360ControllerClass::setReport(IOMemoryDescriptor *report,IOHIDReportType reportType,IOOptionBits options) +{ + char data[2]; + + report->readBytes(0,data,2); + switch(data[0]) { + case 0x00: // Set force feedback + if((data[1]!=report->getLength())||(data[1]!=0x04)) return kIOReturnUnsupported; + { + XBOX360_OUT_RUMBLE rumble; + + Xbox360_Prepare(rumble,outRumble); + report->readBytes(2,data,2); + rumble.big=data[0]; + rumble.little=data[1]; + GetOwner(this)->QueueWrite(&rumble,sizeof(rumble)); +// IOLog("Set rumble: big(%d) little(%d)\n", rumble.big, rumble.little); + } + return kIOReturnSuccess; + case 0x01: // Set LEDs + if((data[1]!=report->getLength())||(data[1]!=0x03)) return kIOReturnUnsupported; + { + XBOX360_OUT_LED led; + + report->readBytes(2,data,1); + Xbox360_Prepare(led,outLed); + led.pattern=data[0]; + GetOwner(this)->QueueWrite(&led,sizeof(led)); +// IOLog("Set LED: %d\n", led.pattern); + } + return kIOReturnSuccess; + default: + IOLog("Unknown escape %d\n", data[0]); + return kIOReturnUnsupported; + } +} + +// Get report +IOReturn Xbox360ControllerClass::getReport(IOMemoryDescriptor *report,IOHIDReportType reportType,IOOptionBits options) +{ + // Doesn't do anything yet ;) + return kIOReturnUnsupported; +} + +// Returns the string for the specified index from the USB device's string list, with an optional default +OSString* Xbox360ControllerClass::getDeviceString(UInt8 index,const char *def) const +{ + IOReturn err; + char buf[1024]; + const char *string; + + err = GetOwnerProvider(this)->GetStringDescriptor(index,buf,sizeof(buf)); + if(err==kIOReturnSuccess) string=buf; + else { + if(def==NULL) string="Unknown"; + else string=def; + } + return OSString::withCString(string); +} + +OSString* Xbox360ControllerClass::newManufacturerString() const +{ + return getDeviceString(GetOwnerProvider(this)->GetManufacturerStringIndex()); +} + +OSNumber* Xbox360ControllerClass::newPrimaryUsageNumber() const +{ + return OSNumber::withNumber(HID_360::ReportDescriptor[3], 8); +} + +OSNumber* Xbox360ControllerClass::newPrimaryUsagePageNumber() const +{ + return OSNumber::withNumber(HID_360::ReportDescriptor[1], 8); +} + +OSNumber* Xbox360ControllerClass::newProductIDNumber() const +{ + return OSNumber::withNumber(GetOwnerProvider(this)->GetProductID(),16); +} + +OSString* Xbox360ControllerClass::newProductString() const +{ + return getDeviceString(GetOwnerProvider(this)->GetProductStringIndex()); +} + +OSString* Xbox360ControllerClass::newSerialNumberString() const +{ + return getDeviceString(GetOwnerProvider(this)->GetSerialNumberStringIndex()); +} + +OSString* Xbox360ControllerClass::newTransportString() const +{ + return OSString::withCString("USB"); +} + +OSNumber* Xbox360ControllerClass::newVendorIDNumber() const +{ + return OSNumber::withNumber(GetOwnerProvider(this)->GetVendorID(),16); +} + +OSNumber* Xbox360ControllerClass::newLocationIDNumber() const +{ + IOUSBDevice *device; + OSNumber *number; + UInt32 location; + + device = GetOwnerProvider(this); + if (device) + { + if ((number = OSDynamicCast(OSNumber, device->getProperty("locationID")))) + { + location = number->unsigned32BitValue(); + } + else + { + // Make up an address + if ((number = OSDynamicCast(OSNumber, device->getProperty("USB Address")))) + location |= number->unsigned8BitValue() << 24; + + if ((number = OSDynamicCast(OSNumber, device->getProperty("idProduct")))) + location |= number->unsigned8BitValue() << 16; + } + } + + return (location != 0) ? OSNumber::withNumber(location, 32) : 0; +} diff --git a/360Controller/Controller.h b/360Controller/Controller.h new file mode 100644 index 00000000..0ac4321b --- /dev/null +++ b/360Controller/Controller.h @@ -0,0 +1,53 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + Controller.h - Driver class for the 360 controller + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include + +class Xbox360ControllerClass : public IOHIDDevice +{ + OSDeclareDefaultStructors(Xbox360ControllerClass) + +private: + OSString* getDeviceString(UInt8 index,const char *def=NULL) const; + +public: + virtual bool start(IOService *provider); + + virtual IOReturn setProperties(OSObject *properties); + + virtual IOReturn newReportDescriptor(IOMemoryDescriptor **descriptor) const; + + virtual IOReturn setReport(IOMemoryDescriptor *report,IOHIDReportType reportType,IOOptionBits options=0); + virtual IOReturn getReport(IOMemoryDescriptor *report,IOHIDReportType reportType,IOOptionBits options); + + virtual OSString* newManufacturerString() const; + virtual OSNumber* newPrimaryUsageNumber() const; + virtual OSNumber* newPrimaryUsagePageNumber() const; + virtual OSNumber* newProductIDNumber() const; + virtual OSString* newProductString() const; + virtual OSString* newSerialNumberString() const; + virtual OSString* newTransportString() const; + virtual OSNumber* newVendorIDNumber() const; + + virtual OSNumber* newLocationIDNumber() const; +}; diff --git a/360Controller/English.lproj/InfoPlist.strings b/360Controller/English.lproj/InfoPlist.strings new file mode 100644 index 00000000..068787ee --- /dev/null +++ b/360Controller/English.lproj/InfoPlist.strings @@ -0,0 +1,4 @@ +/* Localized versions of Info.plist keys */ + +CFBundleName = "360Controller"; +NSHumanReadableCopyright = "© Colin Munro, 2005-11"; \ No newline at end of file diff --git a/360Controller/Info copy.plist b/360Controller/Info copy.plist new file mode 100644 index 00000000..b06cc87e --- /dev/null +++ b/360Controller/Info copy.plist @@ -0,0 +1,56 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + 360Controller + CFBundleIconFile + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + KEXT + CFBundleSignature + ???? + CFBundleVersion + 1.0.0d1 + IOKitPersonalities + + Controller + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360ControllerClass + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 654 + idVendor + 1118 + + + OSBundleLibraries + + com.apple.iokit.IOHIDFamily + 1.2 + com.apple.iokit.IOUSBFamily + 1.8 + com.apple.kernel.libkern + 6.9.9 + com.apple.kernel.mach + 6.9.9 + + + diff --git a/360Controller/Info.plist b/360Controller/Info.plist new file mode 100644 index 00000000..681fbe73 --- /dev/null +++ b/360Controller/Info.plist @@ -0,0 +1,1453 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + KEXT + CFBundleSignature + ???? + CFBundleVersion + 1.0.0d12 + IOKitPersonalities + + AfterglowGamepadforXbox360 + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 275 + idVendor + 3695 + + AfterglowGamepadforXbox360Z + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 531 + idVendor + 3695 + + AfterglowGamepadforXbox360ZZ + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 63744 + idVendor + 7085 + + AviatorforXbox360PC + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 52009 + idVendor + 1848 + + BatarangwiredcontrollerXBOX + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 16144 + idVendor + 5604 + + BigbenControllerBB7201 + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 1537 + idVendor + 5227 + + ChatPadKeyboardEvents + + CFBundleIdentifier + com.apple.iokit.IOHIDFamily + IOClass + IOHIDEventDriver + IOProviderClass + IOHIDInterface + VendorID + 100 + + Controller + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 62465 + idVendor + 1848 + + ControllerZ + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 62721 + idVendor + 3695 + + ControllerZZ + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 63489 + idVendor + 5168 + + ControllerZZZ + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 654 + idVendor + 7085 + + ControllerZZZZ + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 64001 + idVendor + 7085 + + DDRUniverse2Mat + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 4 + idVendor + 4779 + + Ferrari458Racingwheel + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 23296 + idVendor + 9414 + + GH4Guitar + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 18228 + idVendor + 5168 + + GamepadF310 + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 49693 + idVendor + 1133 + + GamepadforXbox360 + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 769 + idVendor + 3695 + + GamepadforXbox360Z + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 1025 + idVendor + 3695 + + GamepadforXbox360ZZ + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 770 + idVendor + 4779 + + GamepadforXbox360ZZZ + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 63746 + idVendor + 7085 + + GamestopXbox360Controller + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 63745 + idVendor + 7085 + + GuitarHeroforPCMAC + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 18252 + idVendor + 5168 + + HORIPADEX2TURBO + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 62721 + idVendor + 7085 + + HarmonixDrumKitforXbox360 + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 3 + idVendor + 7085 + + HarmonixGuitarforXbox360 + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 2 + idVendor + 7085 + + HoriCoDOA4FightStick + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 10 + idVendor + 3853 + + HoriFightingStickEx2 + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 13 + idVendor + 3853 + + HoriRealArcadeProEx + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 22 + idVendor + 3853 + + HoriRealArcadeProVXSA + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 21761 + idVendor + 9414 + + HoriSOULCALIBURVStick + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 21766 + idVendor + 9414 + + JoytechNeoSe + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 61485 + idVendor + 7085 + + JoytechNeoSeTake2 + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 48879 + idVendor + 5678 + + LogitechChillStream + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 49730 + idVendor + 1133 + + LogitechF510 + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 49694 + idVendor + 1133 + + MadCatz360 + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 64769 + idVendor + 7085 + + MadCatzBeatPad + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 18240 + idVendor + 1848 + + MadCatzCallofDutyGamePad + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 61477 + idVendor + 7085 + + MadCatzFPSProGamePad + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 61479 + idVendor + 7085 + + MadCatzGhostReconFSGamePad + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 61473 + idVendor + 7085 + + MadCatzMicroConGamePadPro + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 18230 + idVendor + 1848 + + MadCatzMicroConGamePadProZ + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 61494 + idVendor + 7085 + + MadCatzPortableDrumKit + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 39025 + idVendor + 1848 + + MadCatzStreetFighterIVFightPad + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 18216 + idVendor + 1848 + + MadCatzStreetFighterIVFightStickSE + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 18200 + idVendor + 1848 + + MadCatzXbox360Controller + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 18198 + idVendor + 1848 + + MadCatzXbox360ControllerZ + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 18214 + idVendor + 1848 + + MadCatzXbox360ControllerZZ + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 48879 + idVendor + 1848 + + MadCatzXbox360ControllerZZZ + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 61462 + idVendor + 7085 + + MadCatzXboxcontrollerMW2 + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 46886 + idVendor + 1848 + + MicrosoftXbox360Controller + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 654 + idVendor + 1118 + + PDPAFTERGLOWAX1 + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 769 + idVendor + 4779 + + PDPDancePad + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 261 + idVendor + 3695 + + PelicanTSZ360Pad + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 513 + idVendor + 3695 + + PowerAMiniProElite + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 16128 + idVendor + 5604 + + PowerAMiniProEliteGlow + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 21248 + idVendor + 9414 + + REALARCADEPROEX + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 62724 + idVendor + 7085 + + REALARCADEProVX + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 62722 + idVendor + 7085 + + RazerOnza + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 64768 + idVendor + 5769 + + RazerOnzaTournamentEdition + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 64769 + idVendor + 5769 + + RedOctaneGuitarHeroXplorer + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 18248 + idVendor + 5168 + + RockCandyGamepadforXbox360 + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 287 + idVendor + 3695 + + RockRevolutionforXbox360 + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 6 + idVendor + 4779 + + SaitekCyborgRumblePadPCXbox360 + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 51970 + idVendor + 1848 + + SaitekP3200RumblePadPCXbox360 + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 51971 + idVendor + 1848 + + StreetFighterIVFightPad + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 61480 + idVendor + 7085 + + StreetFighterIVFightStickTE + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 18232 + idVendor + 1848 + + SuperSFIVFightStickTES + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 63288 + idVendor + 1848 + + TronXbox360controller + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 63747 + idVendor + 7085 + + USBGamepad + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 21760 + idVendor + 7085 + + XB360MortalKombatFightStick + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 63750 + idVendor + 7085 + + XboxAirflowiredcontroller + + CFBundleIdentifier + com.mice.driver.Xbox360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Xbox360Peripheral + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + idProduct + 16138 + idVendor + 5604 + + + NSHumanReadableCopyright + Copyright © 2013 MICE Software. All rights reserved. + OSBundleLibraries + + com.apple.iokit.IOHIDFamily + 1.2 + com.apple.iokit.IOUSBFamily + 1.8 + com.apple.kpi.iokit + 8.0.0 + com.apple.kpi.libkern + 8.0.0 + com.apple.kpi.mach + 8.0.0 + + + diff --git a/360Controller/_60Controller.cpp b/360Controller/_60Controller.cpp new file mode 100644 index 00000000..faecb563 --- /dev/null +++ b/360Controller/_60Controller.cpp @@ -0,0 +1,861 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + Bug fixes contributed by Cody "codeman38" Boisclair + + _60Controller.cpp - main source of the driver + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include +#include +#include +#include "_60Controller.h" +#include "ControlStruct.h" +#include "ChatPad.h" +#include "Controller.h" + +#define kDriverSettingKey "DeviceData" + +#define kIOSerialDeviceType "Serial360Device" + +OSDefineMetaClassAndStructors(Xbox360Peripheral, IOService) +#define super IOService + +class LockRequired +{ +private: + IOLock *_lock; +public: + LockRequired(IOLock *lock) + { + _lock = lock; + IOLockLock(_lock); + } + ~LockRequired() + { + IOLockUnlock(_lock); + } +}; + +// Find the maximum packet size of this pipe +static UInt32 GetMaxPacketSize(IOUSBPipe *pipe) +{ + const IOUSBEndpointDescriptor *ed; + + ed=pipe->GetEndpointDescriptor(); + if(ed==NULL) return 0; + else return ed->wMaxPacketSize; +} + +void Xbox360Peripheral::SendSpecial(UInt16 value) +{ + IOUSBDevRequest controlReq; + + controlReq.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBInterface); + controlReq.bRequest = 0x00; + controlReq.wValue = value; + controlReq.wIndex = 0x0002; + controlReq.wLength = 0; + controlReq.pData = NULL; + if (device->DeviceRequest(&controlReq, 100, 100, NULL) != kIOReturnSuccess) + IOLog("Failed to send special message %.4x\n", value); +} + +void Xbox360Peripheral::SendInit(UInt16 value, UInt16 index) +{ + IOUSBDevRequest controlReq; + + controlReq.bmRequestType = USBmakebmRequestType(kUSBOut, kUSBVendor, kUSBDevice); + controlReq.bRequest = 0xa9; + controlReq.wValue = value; + controlReq.wIndex = index; + controlReq.wLength = 0; + controlReq.pData = NULL; + device->DeviceRequest(&controlReq, 100, 100, NULL); // Will fail - but device should still act on it +} + +bool Xbox360Peripheral::SendSwitch(bool sendOut) +{ + IOUSBDevRequest controlReq; + + controlReq.bmRequestType = USBmakebmRequestType(sendOut ? kUSBOut : kUSBIn, kUSBVendor, kUSBDevice); + controlReq.bRequest = 0xa1; + controlReq.wValue = 0x0000; + controlReq.wIndex = 0xe416; + controlReq.wLength = sizeof(chatpadInit); + controlReq.pData = chatpadInit; + if (device->DeviceRequest(&controlReq, 100, 100, NULL) == kIOReturnSuccess) + return true; + IOLog("start - failed to %s chatpad setting\n", sendOut ? "write" : "read"); + return false; +} + +void Xbox360Peripheral::SendToggle(void) +{ + SendSpecial(serialToggle ? 0x1F : 0x1E); + serialToggle = !serialToggle; +} + +void Xbox360Peripheral::ChatPadTimerActionWrapper(OSObject *owner, IOTimerEventSource *sender) +{ + Xbox360Peripheral *controller; + + controller = OSDynamicCast(Xbox360Peripheral, owner); + controller->ChatPadTimerAction(sender); +} + +void Xbox360Peripheral::ChatPadTimerAction(IOTimerEventSource *sender) +{ + int nextTime, serialGot; + + serialGot = 0; + nextTime = 1000; + switch (serialTimerState) + { + case tsToggle: + SendToggle(); + if (serialActive) + { + if (!serialHeard) + { + serialActive = false; + serialGot = 2; + } + } + else + { + if (serialHeard) + { + serialTimerState = tsReset1; + serialResetCount = 0; + nextTime = 40; + } + } + break; + + case tsMiniToggle: + SendToggle(); + if (serialHeard) + { + serialTimerState = tsSet1; + nextTime = 40; + } + else + { + serialResetCount++; + if (serialResetCount > 3) + { + serialTimerState = tsToggle; + } + else + { + serialTimerState = tsReset1; + nextTime = 40; + } + } + break; + + case tsReset1: + SendSpecial(0x1B); + serialTimerState = tsReset2; + nextTime = 35; + break; + + case tsReset2: + SendSpecial(0x1B); + serialTimerState = tsMiniToggle; + nextTime = 150; + break; + + case tsSet1: + SendSpecial(0x18); + serialTimerState = tsSet2; + nextTime = 10; + break; + + case tsSet2: + SendSpecial(0x10); + serialTimerState = tsSet3; + nextTime = 10; + break; + + case tsSet3: + SendSpecial(0x03); + serialTimerState = tsToggle; + nextTime = 940; + serialActive = true; + serialGot = 1; + break; + } + sender->setTimeoutMS(nextTime); // Todo: Make it take into account function execution time? + serialHeard = false; + // Make it happen after the timer's set, for minimum impact + switch (serialGot) + { + case 1: + SerialConnect(); + break; + + case 2: + SerialDisconnect(); + break; + + default: + break; + } +} + +// Read the settings from the registry +void Xbox360Peripheral::readSettings(void) +{ + OSDictionary *dataDictionary; + OSBoolean *value; + OSNumber *number; + + dataDictionary=OSDynamicCast(OSDictionary,getProperty(kDriverSettingKey)); + if(dataDictionary==NULL) return; + value=OSDynamicCast(OSBoolean,dataDictionary->getObject("InvertLeftX")); + if(value!=NULL) invertLeftX=value->getValue(); + value=OSDynamicCast(OSBoolean,dataDictionary->getObject("InvertLeftY")); + if(value!=NULL) invertLeftY=value->getValue(); + value=OSDynamicCast(OSBoolean,dataDictionary->getObject("InvertRightX")); + if(value!=NULL) invertRightX=value->getValue(); + value=OSDynamicCast(OSBoolean,dataDictionary->getObject("InvertRightY")); + if(value!=NULL) invertRightY=value->getValue(); + number=OSDynamicCast(OSNumber,dataDictionary->getObject("DeadzoneLeft")); + if(number!=NULL) deadzoneLeft=number->unsigned32BitValue(); + number=OSDynamicCast(OSNumber,dataDictionary->getObject("DeadzoneRight")); + if(number!=NULL) deadzoneRight=number->unsigned32BitValue(); + value=OSDynamicCast(OSBoolean,dataDictionary->getObject("RelativeLeft")); + if(value!=NULL) relativeLeft=value->getValue(); + value=OSDynamicCast(OSBoolean,dataDictionary->getObject("RelativeRight")); + if(value!=NULL) relativeRight=value->getValue(); + /* + IOLog("Xbox360Peripheral preferences loaded:\n invertLeft X: %s, Y: %s\n invertRight X: %s, Y:%s\n deadzone Left: %d, Right: %d\n\n", + invertLeftX?"True":"False",invertLeftY?"True":"False", + invertRightX?"True":"False",invertRightY?"True":"False", + deadzoneLeft,deadzoneRight); + */ +} + +// Initialise the extension +bool Xbox360Peripheral::init(OSDictionary *propTable) +{ + bool res=super::init(propTable); + mainLock = IOLockAlloc(); + device=NULL; + interface=NULL; + inPipe=NULL; + outPipe=NULL; + inBuffer=NULL; + padHandler = NULL; + serialIn = NULL; + serialInPipe = NULL; + serialInBuffer = NULL; + serialTimer = NULL; + serialHandler = NULL; + // Default settings + invertLeftX=invertLeftY=FALSE; + invertRightX=invertRightY=FALSE; + deadzoneLeft=deadzoneRight=0; + relativeLeft=relativeRight=FALSE; + // Done + return res; +} + +// Free the extension +void Xbox360Peripheral::free(void) +{ + IOLockFree(mainLock); + super::free(); +} + +bool Xbox360Peripheral::start(IOService *provider) +{ + const IOUSBConfigurationDescriptor *cd; + IOUSBFindInterfaceRequest intf; + IOUSBFindEndpointRequest pipe; + XBOX360_OUT_LED led; + IOWorkLoop *workloop = NULL; + + if (!super::start(provider)) + return false; + // Get device + device=OSDynamicCast(IOUSBDevice,provider); + if(device==NULL) { + IOLog("start - invalid provider\n"); + goto fail; + } + // Check for configurations + if(device->GetNumConfigurations()<1) { + device=NULL; + IOLog("start - device has no configurations!\n"); + goto fail; + } + // Set configuration + cd=device->GetFullConfigurationDescriptor(0); + if(cd==NULL) { + device=NULL; + IOLog("start - couldn't get configuration descriptor\n"); + goto fail; + } + // Open + if(!device->open(this)) { + device=NULL; + IOLog("start - unable to open device\n"); + goto fail; + } + if(device->SetConfiguration(this,cd->bConfigurationValue,true)!=kIOReturnSuccess) { + IOLog("start - unable to set configuration\n"); + goto fail; + } + // Get release + { + UInt16 release = device->GetDeviceRelease(); + switch (release) { + default: + IOLog("Unknown device release %.4x", release); + // fall through + case 0x0110: + chatpadInit[0] = 0x01; + chatpadInit[1] = 0x02; + break; + case 0x0114: + chatpadInit[0] = 0x09; + chatpadInit[1] = 0x00; + break; + } + } + // Find correct interface + intf.bInterfaceClass=kIOUSBFindInterfaceDontCare; + intf.bInterfaceSubClass=93; + intf.bInterfaceProtocol=1; + intf.bAlternateSetting=kIOUSBFindInterfaceDontCare; + interface=device->FindNextInterface(NULL,&intf); + if(interface==NULL) { + IOLog("start - unable to find the interface\n"); + goto fail; + } + interface->open(this); + // Find pipes + pipe.direction=kUSBIn; + pipe.interval=0; + pipe.type=kUSBInterrupt; + pipe.maxPacketSize=0; + inPipe=interface->FindNextPipe(NULL,&pipe); + if(inPipe==NULL) { + IOLog("start - unable to find in pipe\n"); + goto fail; + } + inPipe->retain(); + pipe.direction=kUSBOut; + outPipe=interface->FindNextPipe(NULL,&pipe); + if(outPipe==NULL) { + IOLog("start - unable to find out pipe\n"); + goto fail; + } + outPipe->retain(); + // Get a buffer + inBuffer=IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task,0,GetMaxPacketSize(inPipe)); + if(inBuffer==NULL) { + IOLog("start - failed to allocate input buffer\n"); + goto fail; + } + // Find chatpad interface + intf.bInterfaceClass = kIOUSBFindInterfaceDontCare; + intf.bInterfaceSubClass = 93; + intf.bInterfaceProtocol = 2; + intf.bAlternateSetting = kIOUSBFindInterfaceDontCare; + serialIn = device->FindNextInterface(NULL, &intf); + if (serialIn == NULL) { + IOLog("start - unable to find chatpad interface\n"); + goto nochat; + } + serialIn->open(this); + // Find chatpad pipe + pipe.direction = kUSBIn; + pipe.interval = 0; + pipe.type = kUSBInterrupt; + pipe.maxPacketSize = 0; + serialInPipe = serialIn->FindNextPipe(NULL, &pipe); + if (serialInPipe == NULL) + { + IOLog("start - unable to find chatpad in pipe\n"); + goto fail; + } + serialInPipe->retain(); + // Get a buffer for the chatpad + serialInBuffer = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, 0, GetMaxPacketSize(serialInPipe)); + if (serialInBuffer == NULL) + { + IOLog("start - failed to allocate input buffer for chatpad\n"); + goto fail; + } + // Create timer for chatpad + serialTimer = IOTimerEventSource::timerEventSource(this, ChatPadTimerActionWrapper); + if (serialTimer == NULL) + { + IOLog("start - failed to create timer for chatpad\n"); + goto fail; + } + workloop = getWorkLoop(); + if ((workloop == NULL) || (workloop->addEventSource(serialTimer) != kIOReturnSuccess)) + { + IOLog("start - failed to connect timer for chatpad\n"); + goto fail; + } + // Configure ChatPad + // Send 'configuration' + SendInit(0xa30c, 0x4423); + SendInit(0x2344, 0x7f03); + SendInit(0x5839, 0x6832); + // Set 'switch' + if ((!SendSwitch(false)) || (!SendSwitch(true)) || (!SendSwitch(false))) + goto fail; + // Begin toggle + serialHeard = false; + serialActive = false; + serialToggle = false; + serialResetCount = 0; + serialTimerState = tsToggle; + serialTimer->setTimeoutMS(1000); + // Begin reading + if (!QueueSerialRead()) + goto fail; +nochat: + if (!QueueRead()) + goto fail; + // Disable LED + Xbox360_Prepare(led,outLed); + led.pattern=ledOff; + QueueWrite(&led,sizeof(led)); + // Done + PadConnect(); + registerService(); + return true; +fail: + ReleaseAll(); + return false; +} + +// Set up an asynchronous read +bool Xbox360Peripheral::QueueRead(void) +{ + IOUSBCompletion complete; + IOReturn err; + + if ((inPipe == NULL) || (inBuffer == NULL)) + return false; + complete.target=this; + complete.action=ReadCompleteInternal; + complete.parameter=inBuffer; + err=inPipe->Read(inBuffer,0,0,inBuffer->getLength(),&complete); + if(err==kIOReturnSuccess) return true; + else { + IOLog("read - failed to start (0x%.8x)\n",err); + return false; + } +} + +bool Xbox360Peripheral::QueueSerialRead(void) +{ + IOUSBCompletion complete; + IOReturn err; + + if ((serialInPipe == NULL) || (serialInBuffer == NULL)) + return false; + complete.target = this; + complete.action = SerialReadCompleteInternal; + complete.parameter = serialInBuffer; + err = serialInPipe->Read(serialInBuffer, 0, 0, serialInBuffer->getLength(), &complete); + if (err == kIOReturnSuccess) + { + return true; + } + else + { + IOLog("read - failed to start for chatpad (0x%.8x)\n",err); + return false; + } +} + +// Set up an asynchronous write +bool Xbox360Peripheral::QueueWrite(const void *bytes,UInt32 length) +{ + IOBufferMemoryDescriptor *outBuffer; + IOUSBCompletion complete; + IOReturn err; + + outBuffer=IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task,0,length); + if(outBuffer==NULL) { + IOLog("send - unable to allocate buffer\n"); + return false; + } + outBuffer->writeBytes(0,bytes,length); + complete.target=this; + complete.action=WriteCompleteInternal; + complete.parameter=outBuffer; + err=outPipe->Write(outBuffer,0,0,length,&complete); + if(err==kIOReturnSuccess) return true; + else { + IOLog("send - failed to start (0x%.8x)\n",err); + return false; + } +} + +void Xbox360Peripheral::stop(IOService *provider) +{ + ReleaseAll(); + super::stop(provider); +} + +// Releases all the objects used +void Xbox360Peripheral::ReleaseAll(void) +{ + LockRequired locker(mainLock); + + SerialDisconnect(); + PadDisconnect(); + if (serialTimer != NULL) + { + serialTimer->cancelTimeout(); + getWorkLoop()->removeEventSource(serialTimer); + serialTimer->release(); + serialTimer = NULL; + } + if (serialInPipe != NULL) + { + serialInPipe->Abort(); + serialInPipe->release(); + serialInPipe = NULL; + } + if (serialInBuffer != NULL) + { + serialInBuffer->release(); + serialInBuffer = NULL; + } + if (serialIn != NULL) + { + serialIn->close(this); + serialIn = NULL; + } + if(outPipe!=NULL) { + outPipe->Abort(); + outPipe->release(); + outPipe=NULL; + } + if(inPipe!=NULL) { + inPipe->Abort(); + inPipe->release(); + inPipe=NULL; + } + if(inBuffer!=NULL) { + inBuffer->release(); + inBuffer=NULL; + } + if(interface!=NULL) { + interface->close(this); + interface=NULL; + } + if(device!=NULL) { + device->close(this); + device=NULL; + } +} + +// Handle message sent to the driver +IOReturn Xbox360Peripheral::message(UInt32 type,IOService *provider,void *argument) +{ + switch(type) { + case kIOMessageServiceIsTerminated: + case kIOMessageServiceIsRequestingClose: + if(device->isOpen(this)) ReleaseAll(); + return kIOReturnSuccess; + default: + return super::message(type,provider,argument); + } +} + +// This returns the abs() value of a short, swapping it if necessary +static inline XBox360_SShort getAbsolute(XBox360_SShort value) +{ + XBox360_SShort reverse; + +#ifdef __LITTLE_ENDIAN__ + reverse=value; +#elif __BIG_ENDIAN__ + reverse=((value&0xFF00)>>8)|((value&0x00FF)<<8); +#else +#error Unknown CPU byte order +#endif + return (reverse<0)?~reverse:reverse; +} + +// Adjusts the report for any settings speciified by the user +void Xbox360Peripheral::fiddleReport(IOBufferMemoryDescriptor *buffer) +{ + XBOX360_IN_REPORT *report=(XBOX360_IN_REPORT*)buffer->getBytesNoCopy(); + if(invertLeftX) report->left.x=~report->left.x; + if(!invertLeftY) report->left.y=~report->left.y; + if(invertRightX) report->right.x=~report->right.x; + if(!invertRightY) report->right.y=~report->right.y; + if(deadzoneLeft!=0) { + if(relativeLeft) { + if((getAbsolute(report->left.x)left.y)left.x=0; + report->left.y=0; + } + } else { + if(getAbsolute(report->left.x)left.x=0; + if(getAbsolute(report->left.y)left.y=0; + } + } + if(deadzoneRight!=0) { + if(relativeRight) { + if((getAbsolute(report->right.x)right.y)right.x=0; + report->right.y=0; + } + } else { + if(getAbsolute(report->right.x)right.x=0; + if(getAbsolute(report->right.y)right.y=0; + } + } +} + +// This forwards a completed read notification to a member function +void Xbox360Peripheral::ReadCompleteInternal(void *target,void *parameter,IOReturn status,UInt32 bufferSizeRemaining) +{ + if(target!=NULL) + ((Xbox360Peripheral*)target)->ReadComplete(parameter,status,bufferSizeRemaining); +} + +void Xbox360Peripheral::SerialReadCompleteInternal(void *target, void *parameter, IOReturn status, UInt32 bufferSizeRemaining) +{ + if (target != NULL) + ((Xbox360Peripheral*)target)->SerialReadComplete(parameter, status, bufferSizeRemaining); +} + +// This forwards a completed write notification to a member function +void Xbox360Peripheral::WriteCompleteInternal(void *target,void *parameter,IOReturn status,UInt32 bufferSizeRemaining) +{ + if(target!=NULL) + ((Xbox360Peripheral*)target)->WriteComplete(parameter,status,bufferSizeRemaining); +} + +// This handles a completed asynchronous read +void Xbox360Peripheral::ReadComplete(void *parameter,IOReturn status,UInt32 bufferSizeRemaining) +{ + if (padHandler != NULL) // avoid deadlock with release + { + LockRequired locker(mainLock); + IOReturn err; + bool reread=!isInactive(); + + switch(status) { + case kIOReturnOverrun: + IOLog("read - kIOReturnOverrun, clearing stall\n"); + if (inPipe != NULL) + inPipe->ClearStall(); + // Fall through + case kIOReturnSuccess: + if (inBuffer != NULL) + { + const XBOX360_IN_REPORT *report=(const XBOX360_IN_REPORT*)inBuffer->getBytesNoCopy(); + if((report->header.command==inReport)&&(report->header.size==sizeof(XBOX360_IN_REPORT))) { + fiddleReport(inBuffer); + err = padHandler->handleReport(inBuffer, kIOHIDReportTypeInput); + if(err!=kIOReturnSuccess) { + IOLog("read - failed to handle report: 0x%.8x\n",err); + } + } + } + break; + case kIOReturnNotResponding: + IOLog("read - kIOReturnNotResponding\n"); + reread=false; + break; + default: + reread=false; + break; + } + if(reread) QueueRead(); + } +} + +void Xbox360Peripheral::SerialReadComplete(void *parameter, IOReturn status, UInt32 bufferSizeRemaining) +{ + if (padHandler != NULL) // avoid deadlock with release + { + LockRequired locker(mainLock); + bool reread = !isInactive(); + + switch (status) + { + case kIOReturnOverrun: + IOLog("read (serial) - kIOReturnOverrun, clearing stall\n"); + if (serialInPipe != NULL) + serialInPipe->ClearStall(); + // Fall through + case kIOReturnSuccess: + serialHeard = true; + if (serialInBuffer != NULL) + SerialMessage(serialInBuffer, serialInBuffer->getCapacity() - bufferSizeRemaining); + break; + + case kIOReturnNotResponding: + IOLog("read (serial) - kIOReturnNotResponding\n"); + reread = false; + break; + + default: + reread = false; + break; + } + if (reread) + QueueSerialRead(); + } +} + +// Handle a completed asynchronous write +void Xbox360Peripheral::WriteComplete(void *parameter,IOReturn status,UInt32 bufferSizeRemaining) +{ + IOMemoryDescriptor *memory=(IOMemoryDescriptor*)parameter; + if(status!=kIOReturnSuccess) { + IOLog("write - Error writing: 0x%.8x\n",status); + } + memory->release(); +} + + +// Called by the userspace IORegistryEntrySetCFProperties function +IOReturn Xbox360Peripheral::setProperties(OSObject *properties) +{ + OSDictionary *dictionary; + + dictionary=OSDynamicCast(OSDictionary,properties); + if(dictionary!=NULL) { + setProperty(kDriverSettingKey,dictionary); + readSettings(); + return kIOReturnSuccess; + } else return kIOReturnBadArgument; +} + +IOHIDDevice* Xbox360Peripheral::getController(int index) +{ + switch (index) + { + case 0: + return padHandler; + case 1: + return serialHandler; + default: + return NULL; + } +} + +// Main controller support + +void Xbox360Peripheral::PadConnect(void) +{ + PadDisconnect(); + padHandler = new Xbox360ControllerClass; + if (padHandler != NULL) + { + const OSString *keys[] = { + OSString::withCString(kIOSerialDeviceType), + OSString::withCString("IOCFPlugInTypes"), + OSString::withCString("IOKitDebug"), + }; + const OSObject *objects[] = { + OSNumber::withNumber((unsigned long long)1, 32), + getProperty("IOCFPlugInTypes"), + OSNumber::withNumber((unsigned long long)65535, 32), + }; + OSDictionary *dictionary = OSDictionary::withObjects(objects, keys, sizeof(keys) / sizeof(keys[0]), 0); + if (padHandler->init(dictionary)) + { + padHandler->attach(this); + padHandler->start(this); + } + else + { + padHandler->release(); + padHandler = NULL; + } + } +} + +void Xbox360Peripheral::PadDisconnect(void) +{ + if (padHandler != NULL) + { + padHandler->terminate(kIOServiceRequired | kIOServiceSynchronous); + padHandler->release(); + padHandler = NULL; + } +} + +// Serial peripheral support + +void Xbox360Peripheral::SerialConnect(void) +{ + SerialDisconnect(); + serialHandler = new ChatPadKeyboardClass; + if (serialHandler != NULL) + { + const OSString *keys[] = { + OSString::withCString(kIOSerialDeviceType), + }; + const OSObject *objects[] = { + OSNumber::withNumber((unsigned long long)0, 32), + }; + OSDictionary *dictionary = OSDictionary::withObjects(objects, keys, sizeof(keys) / sizeof(keys[0]), 0); + if (serialHandler->init(dictionary)) + { + serialHandler->attach(this); + serialHandler->start(this); + } + else + { + serialHandler->release(); + serialHandler = NULL; + } + } +} + +void Xbox360Peripheral::SerialDisconnect(void) +{ + if (serialHandler != NULL) + { + // Hope it's okay to terminate twice... + serialHandler->terminate(kIOServiceRequired | kIOServiceSynchronous); + serialHandler->release(); + serialHandler = NULL; + } +} + +void Xbox360Peripheral::SerialMessage(IOBufferMemoryDescriptor *data, size_t length) +{ + if (serialHandler != NULL) + { + char *buffer = (char*)data->getBytesNoCopy(); + if ((length == 5) && (buffer[0] == 0x00)) + serialHandler->handleReport(data, kIOHIDReportTypeInput); + } +} diff --git a/360Controller/_60Controller.h b/360Controller/_60Controller.h new file mode 100644 index 00000000..ea02aad9 --- /dev/null +++ b/360Controller/_60Controller.h @@ -0,0 +1,126 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + _60Controller.h - declaration of the driver main class + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef __XBOX360CONTROLLER_H__ +#define __XBOX360CONTROLLER_H__ + +#include +#include +#include + +class Xbox360ControllerClass; +class ChatPadKeyboardClass; + +class Xbox360Peripheral : public IOService +{ + OSDeclareDefaultStructors(Xbox360Peripheral) + +private: + void ReleaseAll(void); + bool QueueRead(void); + bool QueueSerialRead(void); + + static void SerialReadCompleteInternal(void *target,void *parameter,IOReturn status,UInt32 bufferSizeRemaining); + static void ReadCompleteInternal(void *target,void *parameter,IOReturn status,UInt32 bufferSizeRemaining); + static void WriteCompleteInternal(void *target,void *parameter,IOReturn status,UInt32 bufferSizeRemaining); + + void SerialReadComplete(void *parameter, IOReturn status, UInt32 bufferSizeRemaining); + + void fiddleReport(IOBufferMemoryDescriptor *buffer); + + void readSettings(void); + + static void ChatPadTimerActionWrapper(OSObject *owner, IOTimerEventSource *sender); + void ChatPadTimerAction(IOTimerEventSource *sender); + void SendToggle(void); + void SendSpecial(UInt16 value); + void SendInit(UInt16 value, UInt16 index); + bool SendSwitch(bool sendOut); + + void PadConnect(void); + void PadDisconnect(void); + + void SerialConnect(void); + void SerialDisconnect(void); + void SerialMessage(IOBufferMemoryDescriptor *data, size_t length); + +protected: + typedef enum { + tsToggle, + tsReset1, + tsReset2, + tsMiniToggle, + tsSet1, + tsSet2, + tsSet3, + } TIMER_STATE; + + IOUSBDevice *device; + IOLock *mainLock; + + // Joypad + IOUSBInterface *interface; + IOUSBPipe *inPipe,*outPipe; + IOBufferMemoryDescriptor *inBuffer; + + // Keyboard + IOUSBInterface *serialIn; + IOUSBPipe *serialInPipe; + IOBufferMemoryDescriptor *serialInBuffer; + IOTimerEventSource *serialTimer; + bool serialToggle, serialHeard, serialActive; + int serialResetCount; + TIMER_STATE serialTimerState; + ChatPadKeyboardClass *serialHandler; + Xbox360ControllerClass *padHandler; + UInt8 chatpadInit[2]; + + // Settings + bool invertLeftX,invertLeftY; + bool invertRightX,invertRightY; + short deadzoneLeft,deadzoneRight; + bool relativeLeft,relativeRight; + +public: + // this is from the IORegistryEntry - no provider yet + virtual bool init(OSDictionary *propTable); + virtual void free(void); + + bool start(IOService *provider); + void stop(IOService *provider); + + // IOKit methods. These methods are defines in + + virtual IOReturn setProperties(OSObject *properties); + + virtual IOReturn message(UInt32 type, IOService *provider, void *argument); + + // Hooks + virtual void ReadComplete(void *parameter,IOReturn status,UInt32 bufferSizeRemaining); + virtual void WriteComplete(void *parameter,IOReturn status,UInt32 bufferSizeRemaining); + + bool QueueWrite(const void *bytes,UInt32 length); + + IOHIDDevice* getController(int index); +}; + +#endif /* __XBOX360CONTROLLER_H__ */ diff --git a/360Controller/chatpadhid.h b/360Controller/chatpadhid.h new file mode 100755 index 00000000..dec39420 --- /dev/null +++ b/360Controller/chatpadhid.h @@ -0,0 +1,58 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + chatpadhid.h - a HID descriptor for the Microsoft ChatPad accessory + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +// F:\Documents and Settings\Desktop\hid\ChatPad_Keyboard.h + + +char ReportDescriptor[58] = { + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x25, 0x00, // LOGICAL_MAXIMUM (0) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x09, 0xe1, // USAGE (Keyboard LeftShift) + 0x09, 0xe0, // USAGE (Keyboard LeftControl) + 0x09, 0xe2, // USAGE (Keyboard LeftAlt) + 0x09, 0xe3, // USAGE (Keyboard Left GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x04, // REPORT_COUNT (4) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x04, // REPORT_COUNT (4) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x03, // REPORT_COUNT (3) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xe7, 0x00, // LOGICAL_MAXIMUM (231) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 0xc0 // END_COLLECTION +}; + diff --git a/360Controller/chatpadkeys.cpp b/360Controller/chatpadkeys.cpp new file mode 100644 index 00000000..f97dba06 --- /dev/null +++ b/360Controller/chatpadkeys.cpp @@ -0,0 +1,54 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + chatpadkeys.cpp - Converts a chatpad scancode to a USB key value + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "chatpadkeys.h" + +#define ROW_SIZE 8 + +typedef struct MAP_DATA { + unsigned char row[ROW_SIZE]; +} MAP_DATA; + +static const MAP_DATA columns[] = { +{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, +{0x00, 0x24, 0x23, 0x22, 0x21, 0x20, 0x1F, 0x1E}, +{0x00, 0x18, 0x1C, 0x17, 0x15, 0x08, 0x1A, 0x14}, +{0x00, 0x0D, 0x0B, 0x0A, 0x09, 0x07, 0x16, 0x04}, +{0x00, 0x11, 0x05, 0x19, 0x06, 0x1B, 0x1D, 0x00}, +{0x00, 0x4F, 0x10, 0x37, 0x2C, 0x50, 0x00, 0x00}, +{0x00, 0x00, 0x36, 0x28, 0x13, 0x27, 0x26, 0x25}, +{0x00, 0x2A, 0x0F, 0x00, 0x00, 0x12, 0x0C, 0x0E}, +}; + +unsigned char ChatPad2USB(unsigned char input) +{ + unsigned char row, column; + + row = input & 0x0F; + if (row >= ROW_SIZE) + return 0x00; + column = (input & 0xF0) >> 4; + if (column >= (sizeof(columns) / sizeof(columns[0]))) + return 0x00; + return columns[column].row[row]; +} diff --git a/360Controller/chatpadkeys.h b/360Controller/chatpadkeys.h new file mode 100644 index 00000000..4add680d --- /dev/null +++ b/360Controller/chatpadkeys.h @@ -0,0 +1,24 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + chatpadkeys.h - public functions of the ChatPad key handling + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +unsigned char ChatPad2USB(unsigned char input); diff --git a/360Controller/version.plist b/360Controller/version.plist new file mode 100644 index 00000000..53bf3a3f --- /dev/null +++ b/360Controller/version.plist @@ -0,0 +1,16 @@ + + + + + BuildVersion + 12 + CFBundleVersion + 1.0 + ProductBuildVersion + 7K571 + ProjectName + DevToolsWizardTemplates + SourceVersion + 3870000 + + diff --git a/360Controller/xbox360hid.h b/360Controller/xbox360hid.h new file mode 100644 index 00000000..ccafb6ec --- /dev/null +++ b/360Controller/xbox360hid.h @@ -0,0 +1,125 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + xbox360hid.h - HID descriptor for the driver + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* + * This descriptor was generated using the USB HID definition tool available + * from the USB people's website. It's not quite the same as the HID descriptor + * on the free60.org site as I created this file before I knew about it and + * just kept working with this one anyway :) + */ + +char ReportDescriptor[196] = { + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x05, // USAGE (Game Pad) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x3a, // USAGE (Counted Buffer) + 0xa1, 0x02, // COLLECTION (Logical) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x02, // REPORT_COUNT (2) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x3f, // USAGE (Reserved) + 0x09, 0x3b, // USAGE (Byte Count) + 0x81, 0x01, // INPUT (Cnst,Ary,Abs) + 0x75, 0x01, // REPORT_SIZE (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x45, 0x01, // PHYSICAL_MAXIMUM (1) + 0x95, 0x04, // REPORT_COUNT (4) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x0c, // USAGE_MINIMUM (Button 12) + 0x29, 0x0f, // USAGE_MAXIMUM (Button 15) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x75, 0x01, // REPORT_SIZE (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x45, 0x01, // PHYSICAL_MAXIMUM (1) + 0x95, 0x04, // REPORT_COUNT (4) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x09, 0x09, // USAGE (Button 9) + 0x09, 0x0a, // USAGE (Button 10) + 0x09, 0x07, // USAGE (Button 7) + 0x09, 0x08, // USAGE (Button 8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x75, 0x01, // REPORT_SIZE (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x45, 0x01, // PHYSICAL_MAXIMUM (1) + 0x95, 0x03, // REPORT_COUNT (3) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x09, 0x05, // USAGE (Button 5) + 0x09, 0x06, // USAGE (Button 6) + 0x09, 0x0b, // USAGE (Button 11) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x01, // INPUT (Cnst,Ary,Abs) + 0x75, 0x01, // REPORT_SIZE (1) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x45, 0x01, // PHYSICAL_MAXIMUM (1) + 0x95, 0x04, // REPORT_COUNT (4) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x04, // USAGE_MAXIMUM (Button 4) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x35, 0x00, // PHYSICAL_MINIMUM (0) + 0x46, 0xff, 0x00, // PHYSICAL_MAXIMUM (255) + 0x95, 0x02, // REPORT_COUNT (2) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x32, // USAGE (Z) + 0x09, 0x35, // USAGE (Rz) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x75, 0x10, // REPORT_SIZE (16) + 0x16, 0x00, 0x80, // LOGICAL_MINIMUM (-32768) + 0x26, 0xff, 0x7f, // LOGICAL_MAXIMUM (32767) + 0x36, 0x00, 0x80, // PHYSICAL_MINIMUM (-32768) + 0x46, 0xff, 0x7f, // PHYSICAL_MAXIMUM (32767) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x95, 0x02, // REPORT_COUNT (2) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x01, // USAGE (Pointer) + 0xa1, 0x00, // COLLECTION (Physical) + 0x95, 0x02, // REPORT_COUNT (2) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x33, // USAGE (Rx) + 0x09, 0x34, // USAGE (Ry) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION +}; \ No newline at end of file diff --git a/360Daemon/360Daemon.1 b/360Daemon/360Daemon.1 new file mode 100644 index 00000000..7fc73942 --- /dev/null +++ b/360Daemon/360Daemon.1 @@ -0,0 +1,79 @@ +.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples. +.\"See Also: +.\"man mdoc.samples for a complete listing of options +.\"man mdoc for the short list of editing options +.\"/usr/share/misc/mdoc.template +.Dd 7/8/07 \" DATE +.Dt 360Daemon 1 \" Program name and manual section number +.Os Darwin +.Sh NAME \" Section Header - required - don't modify +.Nm 360Daemon, +.\" The following lines are read in generating the apropos(man -k) database. Use only key +.\" words here as the database is built based on the words here and in the .ND line. +.Nm Other_name_for_same_program(), +.Nm Yet another name for the same program. +.\" Use .Nm macro to designate other names for the documented program. +.Nd This line parsed for whatis database. +.Sh SYNOPSIS \" Section Header - required - don't modify +.Nm +.Op Fl abcd \" [-abcd] +.Op Fl a Ar path \" [-a path] +.Op Ar file \" [file] +.Op Ar \" [file ...] +.Ar arg0 \" Underlined argument - use .Ar anywhere to underline +arg2 ... \" Arguments +.Sh DESCRIPTION \" Section Header - required - don't modify +Use the .Nm macro to refer to your program throughout the man page like such: +.Nm +Underlining is accomplished with the .Ar macro like this: +.Ar underlined text . +.Pp \" Inserts a space +A list of items with descriptions: +.Bl -tag -width -indent \" Begins a tagged list +.It item a \" Each item preceded by .It macro +Description of item a +.It item b +Description of item b +.El \" Ends the list +.Pp +A list of flags and their descriptions: +.Bl -tag -width -indent \" Differs from above in tag removed +.It Fl a \"-a flag as a list item +Description of -a flag +.It Fl b +Description of -b flag +.El \" Ends the list +.Pp +.\" .Sh ENVIRONMENT \" May not be needed +.\" .Bl -tag -width "ENV_VAR_1" -indent \" ENV_VAR_1 is width of the string ENV_VAR_1 +.\" .It Ev ENV_VAR_1 +.\" Description of ENV_VAR_1 +.\" .It Ev ENV_VAR_2 +.\" Description of ENV_VAR_2 +.\" .El +.Sh FILES \" File used or created by the topic of the man page +.Bl -tag -width "/Users/joeuser/Library/really_long_file_name" -compact +.It Pa /usr/share/file_name +FILE_1 description +.It Pa /Users/joeuser/Library/really_long_file_name +FILE_2 description +.El \" Ends the list +.\" .Sh DIAGNOSTICS \" May not be needed +.\" .Bl -diag +.\" .It Diagnostic Tag +.\" Diagnostic informtion here. +.\" .It Diagnostic Tag +.\" Diagnostic informtion here. +.\" .El +.Sh SEE ALSO +.\" List links in ascending order by section, alphabetically within a section. +.\" Please do not reference files that do not exist without filing a bug report +.Xr a 1 , +.Xr b 1 , +.Xr c 1 , +.Xr a 2 , +.Xr b 2 , +.Xr a 3 , +.Xr b 3 +.\" .Sh BUGS \" Document known, unremedied bugs +.\" .Sh HISTORY \" Document history if command behaves in a unique manner \ No newline at end of file diff --git a/360Daemon/360Daemon.m b/360Daemon/360Daemon.m new file mode 100644 index 00000000..abbb1d2c --- /dev/null +++ b/360Daemon/360Daemon.m @@ -0,0 +1,308 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + 360Daemon.m - main functionality of the support daemon + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#import +#import +#import +#import +#import +#include +#import +#include "ControlPrefs.h" + +#define CHECK_SHOWAGAIN @"Do not show this message again" + +#define INSTALL_PATH @"/Library/Application Support/MICE/360Daemon" +#define RESOURCE_PATH INSTALL_PATH @"/Resources" + +mach_port_t masterPort; +IONotificationPortRef notifyPort; +CFRunLoopSourceRef notifySource; +io_iterator_t onIteratorWired; +io_iterator_t onIteratorWireless; +io_iterator_t onIteratorOther; +io_iterator_t offIteratorWired; +io_iterator_t offIteratorWireless; +BOOL foundWirelessReceiver; +NSString *leds[4]; + +CFUserNotificationRef activeAlert = nil; +CFRunLoopSourceRef activeAlertSource; +int activeAlertIndex; + +enum { + kaPlugNCharge = 0, +}; + +NSString *alertStrings[] = { + @"You have attached a Microsoft Play & Charge cable for your XBox 360 Wireless Controller. While this cable will allow you to charge your wireless controller, you will require the Microsoft Wireless Gaming Receiver for Windows to use your wireless controller in Mac OS X!", +}; + +static void releaseAlert(void) +{ + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), activeAlertSource, kCFRunLoopCommonModes); + CFRelease(activeAlertSource); + CFRelease(activeAlert); + activeAlertSource = nil; + activeAlert = nil; +} + +static void callbackAlert(CFUserNotificationRef userNotification, CFOptionFlags responseFlags) +{ + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + + if (responseFlags & CFUserNotificationCheckBoxChecked(0)) + SetAlertDisabled(activeAlertIndex); + releaseAlert(); + [pool release]; +} + +static void ShowAlert(int index) +{ + SInt32 error; + NSArray *checkBoxes = [NSArray arrayWithObjects:CHECK_SHOWAGAIN, nil]; + NSArray *dictKeys = [NSArray arrayWithObjects: + (NSString*)kCFUserNotificationAlertHeaderKey, + (NSString*)kCFUserNotificationAlertMessageKey, + (NSString*)kCFUserNotificationCheckBoxTitlesKey, + (NSString*)kCFUserNotificationIconURLKey, + nil]; + NSArray *dictValues = [NSArray arrayWithObjects: + @"XBox 360 Controller Driver", + alertStrings[index], + checkBoxes, + [NSURL fileURLWithPath:RESOURCE_PATH @"/Alert.tif"], + nil]; + NSDictionary *dictionary = [NSDictionary dictionaryWithObjects:dictValues forKeys:dictKeys]; + + if (AlertDisabled(index)) + return; + + if (activeAlert != nil) + { + CFUserNotificationCancel(activeAlert); + releaseAlert(); + } + + activeAlertIndex = index; + activeAlert = CFUserNotificationCreate(kCFAllocatorDefault, 0, kCFUserNotificationPlainAlertLevel, &error, (CFDictionaryRef)dictionary); + activeAlertSource = CFUserNotificationCreateRunLoopSource(kCFAllocatorDefault, activeAlert, callbackAlert, 0); + CFRunLoopAddSource(CFRunLoopGetCurrent(), activeAlertSource, kCFRunLoopCommonModes); +} + +static void ConfigureDevice(io_service_t object) +{ + IOCFPlugInInterface **iodev; + IOUSBDeviceInterface **dev; + IOReturn err; + SInt32 score; + + if ((!IOCreatePlugInInterfaceForService(object, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score))&&iodev) + { + err = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID)&dev); + (*iodev)->Release(iodev); + if ((!err) && dev) + { + if ((*dev)->USBDeviceOpen(dev) == 0) + { + IOUSBConfigurationDescriptorPtr confDesc; + + if ((*dev)->GetConfigurationDescriptorPtr(dev, 0, &confDesc) == 0) + { + (*dev)->SetConfiguration(dev, confDesc->bConfigurationValue); + // Open interface? Hopefully not necessary + } + (*dev)->USBDeviceClose(dev); + } + (*dev)->Release(dev); + } + } +} + +// Supported device - connecting - set settings? +static void callbackConnected(void *param,io_iterator_t iterator) +{ + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + io_service_t object = 0; + + while ((object = IOIteratorNext(iterator)) != 0) + { + /* + CFStringRef bob = IOObjectCopyClass(object); + NSLog(@"Found %p: %@", object, bob); + CFRelease(bob); + */ + if (IOObjectConformsTo(object, "WirelessHIDDevice") || IOObjectConformsTo(object, "Xbox360ControllerClass")) + { + FFDeviceObjectReference forceFeedback; + NSString *serialNumber; + + serialNumber = GetSerialNumber(object); + // Supported device - load settings + ConfigController(object, GetController(serialNumber)); + // Set LEDs + forceFeedback = 0; + if (FFCreateDevice(object, &forceFeedback) != FF_OK) + forceFeedback = 0; + if (forceFeedback != 0) + { + FFEFFESCAPE escape; + unsigned char c; + int i; + + c = 0x0a; + if (serialNumber != nil) + { + for (i = 0; i < 4; i++) + { + if ((leds[i] == nil) || ([leds[i] caseInsensitiveCompare:serialNumber] == NSOrderedSame)) + { + c = 0x06 + i; + if (leds[i] == nil) + leds[i] = [serialNumber retain]; +// NSLog(@"Added controller with LED %i", i); + break; + } + } + } + escape.dwSize = sizeof(escape); + escape.dwCommand = 0x02; + escape.cbInBuffer = sizeof(c); + escape.lpvInBuffer = &c; + escape.cbOutBuffer = 0; + escape.lpvOutBuffer = NULL; + FFDeviceEscape(forceFeedback, &escape); + FFReleaseDevice(forceFeedback); + } + } + else + { + CFTypeRef vendorID = IORegistryEntrySearchCFProperty(object,kIOServicePlane,CFSTR("idVendor"),kCFAllocatorDefault,kIORegistryIterateRecursively | kIORegistryIterateParents); + CFTypeRef productID = IORegistryEntrySearchCFProperty(object,kIOServicePlane,CFSTR("idProduct"),kCFAllocatorDefault,kIORegistryIterateRecursively | kIORegistryIterateParents); + if ((vendorID != NULL) && (productID != NULL)) + { + UInt32 idVendor = [((NSNumber*)vendorID) unsignedIntValue]; + UInt32 idProduct = [((NSNumber*)productID) unsignedIntValue]; + if (idVendor == 0x045e) + { + // Microsoft + switch (idProduct) + { + case 0x028f: // Plug'n'charge cable + if (!foundWirelessReceiver) + ShowAlert(kaPlugNCharge); + ConfigureDevice(object); + break; + case 0x0719: // Microsoft Wireless Gaming Receiver + case 0x0291: // Third party Wireless Gaming Receiver + foundWirelessReceiver = TRUE; + break; + } + } + } + if (vendorID != NULL) + CFRelease(vendorID); + if (productID != NULL) + CFRelease(productID); + } + IOObjectRelease(object); + } + [pool release]; +} + +// Supported device - disconnecting +static void callbackDisconnected(void *param, io_iterator_t iterator) +{ + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + io_service_t object = 0; + NSString *serial; + int i; + + while ((object = IOIteratorNext(iterator)) != 0) + { + /* + CFStringRef bob = IOObjectCopyClass(object); + NSLog(@"Lost %p: %@", object, bob); + CFRelease(bob); + */ + serial = GetSerialNumber(object); + if (serial != nil) + { + for (i = 0; i < 4; i++) + { + if (leds[i] == nil) + continue; + if ([leds[i] caseInsensitiveCompare:serial] == NSOrderedSame) + { + [leds[i] release]; + leds[i] = nil; +// NSLog(@"Removed controller with LED %i", i); + } + } + } + IOObjectRelease(object); + } + [pool release]; +} + +// Entry point +int main (int argc, const char * argv[]) +{ + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + + foundWirelessReceiver = FALSE; + memset(leds, 0, sizeof(leds)); + // Get master port, for accessing I/O Kit + IOMasterPort(MACH_PORT_NULL,&masterPort); + // Set up notification of USB device addition/removal + notifyPort=IONotificationPortCreate(masterPort); + notifySource=IONotificationPortGetRunLoopSource(notifyPort); + CFRunLoopAddSource(CFRunLoopGetCurrent(),notifySource,kCFRunLoopCommonModes); + // Start listening + // USB devices + IOServiceAddMatchingNotification(notifyPort, kIOFirstMatchNotification, IOServiceMatching(kIOUSBDeviceClassName), callbackConnected, NULL, &onIteratorOther); + callbackConnected(NULL, onIteratorOther); + // Wired 360 devices + IOServiceAddMatchingNotification(notifyPort, kIOFirstMatchNotification, IOServiceMatching("Xbox360ControllerClass"), callbackConnected, NULL, &onIteratorWired); + callbackConnected(NULL, onIteratorWired); + IOServiceAddMatchingNotification(notifyPort, kIOTerminatedNotification, IOServiceMatching("Xbox360ControllerClass"), callbackDisconnected, NULL, &offIteratorWired); + callbackDisconnected(NULL, offIteratorWired); + // Wireless 360 devices + IOServiceAddMatchingNotification(notifyPort, kIOFirstMatchNotification, IOServiceMatching("WirelessHIDDevice"), callbackConnected, NULL, &onIteratorWireless); + callbackConnected(NULL, onIteratorWireless); + IOServiceAddMatchingNotification(notifyPort, kIOTerminatedNotification, IOServiceMatching("WirelessHIDDevice"), callbackDisconnected, NULL, &offIteratorWireless); + callbackDisconnected(NULL, offIteratorWireless); + // Run loop + CFRunLoopRun(); + // Stop listening + IOObjectRelease(onIteratorOther); + IOObjectRelease(onIteratorWired); + IOObjectRelease(offIteratorWired); + IOObjectRelease(onIteratorWireless); + IOObjectRelease(offIteratorWireless); + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), notifySource, kCFRunLoopCommonModes); + CFRunLoopSourceInvalidate(notifySource); + IONotificationPortDestroy(notifyPort); + // End + [pool release]; + return 0; +} diff --git a/360Daemon/360Daemon.xcodeproj/project.pbxproj b/360Daemon/360Daemon.xcodeproj/project.pbxproj new file mode 100644 index 00000000..c323444c --- /dev/null +++ b/360Daemon/360Daemon.xcodeproj/project.pbxproj @@ -0,0 +1,248 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 3B7905000CE3F6A400ACB699 /* ForceFeedback.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B7904FF0CE3F6A400ACB699 /* ForceFeedback.framework */; }; + 3B7A8E2C0CE14E38005BB45B /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B7A8E2B0CE14E38005BB45B /* IOKit.framework */; }; + 3B8698090CE2903100283CEC /* ControlPrefs.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B8698080CE2903100283CEC /* ControlPrefs.m */; }; + 8DD76F9A0486AA7600D96B5E /* 360Daemon.m in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* 360Daemon.m */; settings = {ATTRIBUTES = (); }; }; + 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; }; + 8DD76F9F0486AA7600D96B5E /* 360Daemon.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = C6859EA3029092ED04C91782 /* 360Daemon.1 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 8DD76F9E0486AA7600D96B5E /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + 8DD76F9F0486AA7600D96B5E /* 360Daemon.1 in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 08FB7796FE84155DC02AAC07 /* 360Daemon.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = 360Daemon.m; sourceTree = ""; }; + 08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; + 32A70AAB03705E1F00C91783 /* 360Daemon_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = 360Daemon_Prefix.pch; sourceTree = ""; }; + 3B7904D50CE3F13700ACB699 /* Alert.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Alert.tif; sourceTree = ""; }; + 3B7904FF0CE3F6A400ACB699 /* ForceFeedback.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ForceFeedback.framework; path = /System/Library/Frameworks/ForceFeedback.framework; sourceTree = ""; }; + 3B7A8E2B0CE14E38005BB45B /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = ""; }; + 3B8698070CE2903100283CEC /* ControlPrefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ControlPrefs.h; sourceTree = ""; }; + 3B8698080CE2903100283CEC /* ControlPrefs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ControlPrefs.m; sourceTree = ""; }; + 3BBB7EED16C387C600BC7827 /* com.mice.360Daemon.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = com.mice.360Daemon.plist; sourceTree = ""; }; + 8DD76FA10486AA7600D96B5E /* 360Daemon */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = 360Daemon; sourceTree = BUILT_PRODUCTS_DIR; }; + C6859EA3029092ED04C91782 /* 360Daemon.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = 360Daemon.1; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8DD76F9B0486AA7600D96B5E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */, + 3B7A8E2C0CE14E38005BB45B /* IOKit.framework in Frameworks */, + 3B7905000CE3F6A400ACB699 /* ForceFeedback.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* 360Daemon */ = { + isa = PBXGroup; + children = ( + 08FB7795FE84155DC02AAC07 /* Source */, + C6859EA2029092E104C91782 /* Documentation */, + 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */, + 1AB674ADFE9D54B511CA2CBB /* Products */, + ); + name = 360Daemon; + sourceTree = ""; + }; + 08FB7795FE84155DC02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + 3B7904D50CE3F13700ACB699 /* Alert.tif */, + 3B8698070CE2903100283CEC /* ControlPrefs.h */, + 3B8698080CE2903100283CEC /* ControlPrefs.m */, + 32A70AAB03705E1F00C91783 /* 360Daemon_Prefix.pch */, + 08FB7796FE84155DC02AAC07 /* 360Daemon.m */, + 3BBB7EED16C387C600BC7827 /* com.mice.360Daemon.plist */, + ); + name = Source; + sourceTree = ""; + }; + 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + 3B7904FF0CE3F6A400ACB699 /* ForceFeedback.framework */, + 3B7A8E2B0CE14E38005BB45B /* IOKit.framework */, + 08FB779EFE84155DC02AAC07 /* Foundation.framework */, + ); + name = "External Frameworks and Libraries"; + sourceTree = ""; + }; + 1AB674ADFE9D54B511CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8DD76FA10486AA7600D96B5E /* 360Daemon */, + ); + name = Products; + sourceTree = ""; + }; + C6859EA2029092E104C91782 /* Documentation */ = { + isa = PBXGroup; + children = ( + C6859EA3029092ED04C91782 /* 360Daemon.1 */, + ); + name = Documentation; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8DD76F960486AA7600D96B5E /* 360Daemon */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "360Daemon" */; + buildPhases = ( + 8DD76F990486AA7600D96B5E /* Sources */, + 8DD76F9B0486AA7600D96B5E /* Frameworks */, + 8DD76F9E0486AA7600D96B5E /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = 360Daemon; + productInstallPath = "$(HOME)/bin"; + productName = 360Daemon; + productReference = 8DD76FA10486AA7600D96B5E /* 360Daemon */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "360Daemon" */; + compatibilityVersion = "Xcode 2.4"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 08FB7794FE84155DC02AAC07 /* 360Daemon */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8DD76F960486AA7600D96B5E /* 360Daemon */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 8DD76F990486AA7600D96B5E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8DD76F9A0486AA7600D96B5E /* 360Daemon.m in Sources */, + 3B8698090CE2903100283CEC /* ControlPrefs.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1DEB927508733DD40010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = 360Daemon_Prefix.pch; + INSTALL_PATH = "$(HOME)/bin"; + PRODUCT_NAME = 360Daemon; + SDKROOT = ""; + ZERO_LINK = YES; + }; + name = Debug; + }; + 1DEB927608733DD40010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_MODEL_TUNING = G5; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = 360Daemon_Prefix.pch; + INSTALL_PATH = "$(HOME)/bin"; + PRODUCT_NAME = 360Daemon; + }; + name = Release; + }; + 1DEB927908733DD40010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "Developer ID Application: Colin Munro"; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.5; + PREBINDING = NO; + PROVISIONING_PROFILE = ""; + SDKROOT = ""; + }; + name = Debug; + }; + 1DEB927A08733DD40010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + CODE_SIGN_IDENTITY = "Developer ID Application: Colin Munro"; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.5; + PREBINDING = NO; + PROVISIONING_PROFILE = ""; + SDKROOT = ""; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "360Daemon" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB927508733DD40010E9CD /* Debug */, + 1DEB927608733DD40010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "360Daemon" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB927908733DD40010E9CD /* Debug */, + 1DEB927A08733DD40010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/360Daemon/360Daemon_Prefix.pch b/360Daemon/360Daemon_Prefix.pch new file mode 100644 index 00000000..d0b6018a --- /dev/null +++ b/360Daemon/360Daemon_Prefix.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the '360Daemon' target in the '360Daemon' project. +// + +#ifdef __OBJC__ + #import +#endif diff --git a/360Daemon/Alert.tif b/360Daemon/Alert.tif new file mode 100644 index 00000000..d8d477b6 Binary files /dev/null and b/360Daemon/Alert.tif differ diff --git a/360Daemon/ControlPrefs.h b/360Daemon/ControlPrefs.h new file mode 100644 index 00000000..d3ec031a --- /dev/null +++ b/360Daemon/ControlPrefs.h @@ -0,0 +1,45 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + ControlPrefs.h - interface to the preferences functionality + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#import + +#define DOM_DAEMON CFSTR("com.mice.driver.Xbox360Controller.daemon") +#define DOM_CONTROLLERS CFSTR("com.mice.driver.Xbox360Controller.devices") + +#define D_SHOWONCE @"ShowAlert" +#define D_KNOWNDEV @"KnownDevices" + +// Daemon's own settings +void SetAlertDisabled(int index); +BOOL AlertDisabled(int index); + +// Controller settings +void SetController(NSString *serial, NSDictionary *data); +NSDictionary* GetController(NSString *serial); + +// Configuration settings +void SetKnownDevices(NSDictionary *devices); +NSDictionary* GetKnownDevices(void); + +// Utility functions +NSString* GetSerialNumber(io_service_t device); +void ConfigController(io_service_t device, NSDictionary *config); diff --git a/360Daemon/ControlPrefs.m b/360Daemon/ControlPrefs.m new file mode 100644 index 00000000..fe173308 --- /dev/null +++ b/360Daemon/ControlPrefs.m @@ -0,0 +1,102 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + ControlPrefs.m - code to read and write shared preferences + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#import "ControlPrefs.h" + +void SetAlertDisabled(int index) +{ + NSString *prop; + NSNumber *value; + + prop = [NSString stringWithFormat:@"%@%i", D_SHOWONCE, index]; + value = [NSNumber numberWithBool:TRUE]; + CFPreferencesSetValue((CFStringRef)prop, value, DOM_DAEMON, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); + CFPreferencesSynchronize((CFStringRef)DOM_DAEMON, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); +} + +BOOL AlertDisabled(int index) +{ + NSString *prop; + BOOL result; + CFPropertyListRef value; + + result = FALSE; + prop = [NSString stringWithFormat:@"%@%i", D_SHOWONCE, index]; + value = CFPreferencesCopyValue((CFStringRef)prop, DOM_DAEMON, kCFPreferencesCurrentUser, kCFPreferencesCurrentHost); + if (value != NULL) + { + result = [((NSNumber*)value) boolValue]; + CFRelease(value); + } + return result; +} + +void SetController(NSString *serial, NSDictionary *data) +{ + CFPreferencesSetValue((CFStringRef)serial, data, DOM_CONTROLLERS, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); + CFPreferencesSynchronize(DOM_CONTROLLERS, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); +} + +NSDictionary* GetController(NSString *serial) +{ + CFPropertyListRef value; + + CFPreferencesSynchronize(DOM_CONTROLLERS, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); + value = CFPreferencesCopyValue((CFStringRef)serial, DOM_CONTROLLERS, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); + return [((NSDictionary*)value) autorelease]; +} + +NSString* GetSerialNumber(io_service_t device) +{ + CFTypeRef value; + + value = IORegistryEntrySearchCFProperty(device, kIOServicePlane, CFSTR("USB Serial Number"), kCFAllocatorDefault, kIORegistryIterateRecursively); + if (value == NULL) + value = IORegistryEntrySearchCFProperty(device, kIOServicePlane, CFSTR("SerialNumber"), kCFAllocatorDefault, kIORegistryIterateRecursively); + return [((NSString*)value) autorelease]; +} + +void ConfigController(io_service_t device, NSDictionary *config) +{ + IORegistryEntrySetCFProperties(device, config); +} + +void SetKnownDevices(NSDictionary *devices) +{ + // Setting the dictionary should work? + NSData *data = [NSKeyedArchiver archivedDataWithRootObject:devices]; + CFPreferencesSetValue((CFStringRef)D_KNOWNDEV, data, DOM_CONTROLLERS, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); + CFPreferencesSynchronize(DOM_CONTROLLERS, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); +} + +NSDictionary* GetKnownDevices(void) +{ + CFPropertyListRef value; + NSData *data; + + CFPreferencesSynchronize(DOM_CONTROLLERS, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); + value = CFPreferencesCopyValue((CFStringRef)D_KNOWNDEV, DOM_CONTROLLERS, kCFPreferencesAnyUser, kCFPreferencesCurrentHost); + data = [(NSData*)value autorelease]; + if (data == nil) + return nil; + return [NSKeyedUnarchiver unarchiveObjectWithData:data]; +} diff --git a/360Daemon/FoundationTool.pbproj/project.pbxproj b/360Daemon/FoundationTool.pbproj/project.pbxproj new file mode 100644 index 00000000..728d4247 --- /dev/null +++ b/360Daemon/FoundationTool.pbproj/project.pbxproj @@ -0,0 +1,259 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 39; + objects = { + 014CEA4F0018CE4811CA2923 = { + buildRules = ( + ); + buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + ZERO_LINK = YES; + }; + isa = PBXBuildStyle; + name = Development; + }; + 014CEA500018CE4811CA2923 = { + buildRules = ( + ); + buildSettings = { + COPY_PHASE_STRIP = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + ZERO_LINK = NO; + }; + isa = PBXBuildStyle; + name = Deployment; + }; +//010 +//011 +//012 +//013 +//014 +//080 +//081 +//082 +//083 +//084 + 08FB7793FE84155DC02AAC07 = { + buildSettings = { + }; + buildStyles = ( + 014CEA4F0018CE4811CA2923, + 014CEA500018CE4811CA2923, + ); + hasScannedForEncodings = 1; + isa = PBXProject; + mainGroup = 08FB7794FE84155DC02AAC07; + projectDirPath = ""; + targets = ( + 8DD76F960486AA7600D96B5E, + ); + }; + 08FB7794FE84155DC02AAC07 = { + children = ( + 08FB7795FE84155DC02AAC07, + C6859EA2029092E104C91782, + 08FB779DFE84155DC02AAC07, + 1AB674ADFE9D54B511CA2CBB, + ); + isa = PBXGroup; + name = "«PROJECTNAME»"; + refType = 4; + sourceTree = ""; + }; + 08FB7795FE84155DC02AAC07 = { + children = ( + 32A70AAB03705E1F00C91783, + 08FB7796FE84155DC02AAC07, + ); + isa = PBXGroup; + name = Source; + refType = 4; + sourceTree = ""; + }; + 08FB7796FE84155DC02AAC07 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = sourcecode.c.objc; + path = "«PROJECTNAME».m"; + refType = 4; + sourceTree = ""; + }; + 08FB779DFE84155DC02AAC07 = { + children = ( + 08FB779EFE84155DC02AAC07, + ); + isa = PBXGroup; + name = "External Frameworks and Libraries"; + refType = 4; + sourceTree = ""; + }; + 08FB779EFE84155DC02AAC07 = { + fallbackIsa = PBXFileReference; + isa = PBXFrameworkReference; + lastKnownFileType = wrapper.framework; + name = Foundation.framework; + path = /System/Library/Frameworks/Foundation.framework; + refType = 0; + sourceTree = ""; + }; +//080 +//081 +//082 +//083 +//084 +//1A0 +//1A1 +//1A2 +//1A3 +//1A4 + 1AB674ADFE9D54B511CA2CBB = { + children = ( + 8DD76FA10486AA7600D96B5E, + ); + isa = PBXGroup; + name = Products; + refType = 4; + sourceTree = ""; + }; +//1A0 +//1A1 +//1A2 +//1A3 +//1A4 +//320 +//321 +//322 +//323 +//324 + 32A70AAB03705E1F00C91783 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = file; + path = "«PROJECTNAME»_Prefix.pch"; + refType = 4; + sourceTree = ""; + }; +//320 +//321 +//322 +//323 +//324 +//8D0 +//8D1 +//8D2 +//8D3 +//8D4 + 8DD76F960486AA7600D96B5E = { + buildPhases = ( + 8DD76F990486AA7600D96B5E, + 8DD76F9B0486AA7600D96B5E, + 8DD76F9E0486AA7600D96B5E, + ); + buildRules = ( + ); + buildSettings = { + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "«PROJECTNAME»_Prefix.pch"; + INSTALL_PATH = "$(HOME)/bin"; + PRODUCT_NAME = "«PROJECTNAME»"; + }; + dependencies = ( + ); + isa = PBXNativeTarget; + name = "«PROJECTNAME»"; + productInstallPath = "$(HOME)/bin"; + productName = "«PROJECTNAME»"; + productReference = 8DD76FA10486AA7600D96B5E; + productType = "com.apple.product-type.tool"; + }; + 8DD76F990486AA7600D96B5E = { + buildActionMask = 2147483647; + files = ( + 8DD76F9A0486AA7600D96B5E, + ); + isa = PBXSourcesBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + 8DD76F9A0486AA7600D96B5E = { + fileRef = 08FB7796FE84155DC02AAC07; + isa = PBXBuildFile; + settings = { + ATTRIBUTES = ( + ); + }; + }; + 8DD76F9B0486AA7600D96B5E = { + buildActionMask = 2147483647; + files = ( + 8DD76F9C0486AA7600D96B5E, + ); + isa = PBXFrameworksBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + 8DD76F9C0486AA7600D96B5E = { + fileRef = 08FB779EFE84155DC02AAC07; + isa = PBXBuildFile; + settings = { + }; + }; + 8DD76F9E0486AA7600D96B5E = { + buildActionMask = 8; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + 8DD76F9F0486AA7600D96B5E, + ); + isa = PBXCopyFilesBuildPhase; + runOnlyForDeploymentPostprocessing = 1; + }; + 8DD76F9F0486AA7600D96B5E = { + fileRef = C6859EA3029092ED04C91782; + isa = PBXBuildFile; + settings = { + }; + }; + 8DD76FA10486AA7600D96B5E = { + explicitFileType = "compiled.mach-o.executable"; + includeInIndex = 0; + isa = PBXFileReference; + path = "«PROJECTNAME»"; + refType = 3; + sourceTree = BUILT_PRODUCTS_DIR; + }; +//8D0 +//8D1 +//8D2 +//8D3 +//8D4 +//C60 +//C61 +//C62 +//C63 +//C64 + C6859EA2029092E104C91782 = { + children = ( + C6859EA3029092ED04C91782, + ); + isa = PBXGroup; + name = Documentation; + refType = 4; + sourceTree = ""; + }; + C6859EA3029092ED04C91782 = { + isa = PBXFileReference; + lastKnownFileType = file; + path = "«PROJECTNAME».1"; + refType = 4; + sourceTree = ""; + }; + }; + rootObject = 08FB7793FE84155DC02AAC07; +} diff --git a/360Daemon/com.mice.360Daemon.plist b/360Daemon/com.mice.360Daemon.plist new file mode 100644 index 00000000..a0f3a82f --- /dev/null +++ b/360Daemon/com.mice.360Daemon.plist @@ -0,0 +1,16 @@ + + + + + RunAtLoad + + ProgramArguments + + /Library/Application Support/MICE/360Daemon/360Daemon + + KeepAlive + + Label + com.mice.360Daemon + + diff --git a/DriverTool/DriverTool.1 b/DriverTool/DriverTool.1 new file mode 100644 index 00000000..f5b4c86f --- /dev/null +++ b/DriverTool/DriverTool.1 @@ -0,0 +1,79 @@ +.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples. +.\"See Also: +.\"man mdoc.samples for a complete listing of options +.\"man mdoc for the short list of editing options +.\"/usr/share/misc/mdoc.template +.Dd 8/05/2011 \" DATE +.Dt DriverTool 1 \" Program name and manual section number +.Os Darwin +.Sh NAME \" Section Header - required - don't modify +.Nm DriverTool, +.\" The following lines are read in generating the apropos(man -k) database. Use only key +.\" words here as the database is built based on the words here and in the .ND line. +.Nm Other_name_for_same_program(), +.Nm Yet another name for the same program. +.\" Use .Nm macro to designate other names for the documented program. +.Nd This line parsed for whatis database. +.Sh SYNOPSIS \" Section Header - required - don't modify +.Nm +.Op Fl abcd \" [-abcd] +.Op Fl a Ar path \" [-a path] +.Op Ar file \" [file] +.Op Ar \" [file ...] +.Ar arg0 \" Underlined argument - use .Ar anywhere to underline +arg2 ... \" Arguments +.Sh DESCRIPTION \" Section Header - required - don't modify +Use the .Nm macro to refer to your program throughout the man page like such: +.Nm +Underlining is accomplished with the .Ar macro like this: +.Ar underlined text . +.Pp \" Inserts a space +A list of items with descriptions: +.Bl -tag -width -indent \" Begins a tagged list +.It item a \" Each item preceded by .It macro +Description of item a +.It item b +Description of item b +.El \" Ends the list +.Pp +A list of flags and their descriptions: +.Bl -tag -width -indent \" Differs from above in tag removed +.It Fl a \"-a flag as a list item +Description of -a flag +.It Fl b +Description of -b flag +.El \" Ends the list +.Pp +.\" .Sh ENVIRONMENT \" May not be needed +.\" .Bl -tag -width "ENV_VAR_1" -indent \" ENV_VAR_1 is width of the string ENV_VAR_1 +.\" .It Ev ENV_VAR_1 +.\" Description of ENV_VAR_1 +.\" .It Ev ENV_VAR_2 +.\" Description of ENV_VAR_2 +.\" .El +.Sh FILES \" File used or created by the topic of the man page +.Bl -tag -width "/Users/joeuser/Library/really_long_file_name" -compact +.It Pa /usr/share/file_name +FILE_1 description +.It Pa /Users/joeuser/Library/really_long_file_name +FILE_2 description +.El \" Ends the list +.\" .Sh DIAGNOSTICS \" May not be needed +.\" .Bl -diag +.\" .It Diagnostic Tag +.\" Diagnostic informtion here. +.\" .It Diagnostic Tag +.\" Diagnostic informtion here. +.\" .El +.Sh SEE ALSO +.\" List links in ascending order by section, alphabetically within a section. +.\" Please do not reference files that do not exist without filing a bug report +.Xr a 1 , +.Xr b 1 , +.Xr c 1 , +.Xr a 2 , +.Xr b 2 , +.Xr a 3 , +.Xr b 3 +.\" .Sh BUGS \" Document known, unremedied bugs +.\" .Sh HISTORY \" Document history if command behaves in a unique manner \ No newline at end of file diff --git a/DriverTool/DriverTool.m b/DriverTool/DriverTool.m new file mode 100644 index 00000000..6dc6a29f --- /dev/null +++ b/DriverTool/DriverTool.m @@ -0,0 +1,194 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + DriverTool.m - implementation of driver info tweaking tool + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#import + +#define DRIVER_NAME @"360Controller.kext" + +static NSDictionary *infoPlistAttributes = nil; + +static NSString* GetDriverDirectory(void) +{ + NSArray *data = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSSystemDomainMask, YES); + return [[data objectAtIndex:0] stringByAppendingPathComponent:@"Extensions"]; +} + +static NSString* GetDriverConfigPath(NSString *driver) +{ + NSString *root = GetDriverDirectory(); + NSString *driverPath = [root stringByAppendingPathComponent:driver]; + NSString *contents = [driverPath stringByAppendingPathComponent:@"Contents"]; + return [contents stringByAppendingPathComponent:@"Info.plist"]; +} + +static id ReadDriverConfig(NSString *driver) +{ + NSString *filename; + NSError *error = nil; + NSData *data; + NSDictionary *config; + + filename = GetDriverConfigPath(driver); + infoPlistAttributes = [[[NSFileManager defaultManager] attributesOfItemAtPath:filename error:&error] retain]; + if (infoPlistAttributes == nil) + { + NSLog(@"Warning: Failed to read attributes of '%@': %@", + filename, error); + } + data = [NSData dataWithContentsOfFile:filename]; + config = [NSPropertyListSerialization propertyListFromData:data mutabilityOption:0 format:NULL errorDescription:NULL]; + return config; +} + +static void WriteDriverConfig(NSString *driver, id config) +{ + NSString *filename; + NSString *errorString; + NSData *data; + + filename = GetDriverConfigPath(driver); + errorString = nil; + data = [NSPropertyListSerialization dataFromPropertyList:config format:NSPropertyListXMLFormat_v1_0 errorDescription:&errorString]; + if (data == nil) + NSLog(@"Error writing config for driver: %@", errorString); + [errorString release]; + if (![data writeToFile:filename atomically:NO]) + NSLog(@"Failed to write file!"); + if (infoPlistAttributes != nil) + { + NSError *error = nil; + if (![[NSFileManager defaultManager] setAttributes:infoPlistAttributes ofItemAtPath:filename error:&error]) + { + NSLog(@"Error setting attributes on '%@': %@", + filename, error); + } + } +} + +static void ScrubDevices(NSMutableDictionary *devices) +{ + NSMutableArray *deviceKeys; + + deviceKeys = [NSMutableArray arrayWithCapacity:10]; + for (NSString *key in [devices allKeys]) + { + NSDictionary *device = [devices objectForKey:key]; + if ([(NSString*)[device objectForKey:@"IOClass"] compare:@"Xbox360Peripheral"] == NSOrderedSame) + [deviceKeys addObject:key]; + } + [devices removeObjectsForKeys:deviceKeys]; +} + +static id MakeMutableCopy(id object) +{ + return [(id)CFPropertyListCreateDeepCopy( + kCFAllocatorDefault, + (CFTypeRef)object, + kCFPropertyListMutableContainers) autorelease]; +} + +static void AddDevice(NSMutableDictionary *personalities, NSString *name, int vendor, int product) +{ + NSMutableDictionary *controller; + + controller = [NSMutableDictionary dictionaryWithCapacity:10]; + + // Standard + [controller setObject:@"com.mice.driver.Xbox360Controller" + forKey:@"CFBundleIdentifier"]; + [controller setObject:[NSDictionary dictionaryWithObject:@"360Controller.kext/Contents/PlugIns/Feedback360.plugin" + forKey:@"F4545CE5-BF5B-11D6-A4BB-0003933E3E3E"] + forKey:@"IOCFPlugInTypes"]; + [controller setObject:@"Xbox360Peripheral" + forKey:@"IOClass"]; + [controller setObject:@"IOUSBDevice" + forKey:@"IOProviderClass"]; + [controller setObject:[NSNumber numberWithInt:65535] + forKey:@"IOKitDebug"]; + + // Device-specific + [controller setObject:[NSNumber numberWithInt:vendor] + forKey:@"idVendor"]; + [controller setObject:[NSNumber numberWithInt:product] + forKey:@"idProduct"]; + + // Add it to the tree + [personalities setObject:controller + forKey:name]; +} + +static void AddDevices(NSMutableDictionary *personalities, int argc, const char *argv[]) +{ + int i, count; + + count = (argc - 2) / 3; + for (i = 0; i < count; i++) + { + NSString *name = [NSString stringWithCString:argv[(i * 3) + 2] encoding:NSUTF8StringEncoding]; + int vendor = atoi(argv[(i * 3) + 3]); + int product = atoi(argv[(i * 3) + 4]); + AddDevice(personalities, name, vendor, product); + } +} + +int main (int argc, const char * argv[]) { + NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; + + NSDictionary *config = ReadDriverConfig(DRIVER_NAME); + if (argc == 1) + { + // Print out current types + NSDictionary *types; + NSArray *keys; + + types = [config objectForKey:@"IOKitPersonalities"]; + keys = [types allKeys]; + for (NSString *key in keys) + { + NSDictionary *device = [types objectForKey:key]; + if ([(NSString*)[device objectForKey:@"IOClass"] compare:@"Xbox360Peripheral"] != NSOrderedSame) + continue; + fprintf(stdout, "%s,%i,%i\n", + [key UTF8String], + [[device objectForKey:@"idVendor"] intValue], + [[device objectForKey:@"idProduct"] intValue]); + } + } + else if ((argc > 1) && (strcmp(argv[1], "edit") == 0) && (((argc - 2) % 3) == 0)) + { + NSMutableDictionary *saving; + NSMutableDictionary *devices; + + saving = MakeMutableCopy(config); + devices = [saving objectForKey:@"IOKitPersonalities"]; + ScrubDevices(devices); + AddDevices(devices, argc, argv); + WriteDriverConfig(DRIVER_NAME, saving); + + system("/usr/bin/touch /System/Library/Extensions"); + } + else + NSLog(@"Invalid number of parameters (%i)", argc); + + [pool drain]; + return 0; +} diff --git a/DriverTool/DriverTool.xcodeproj/project.pbxproj b/DriverTool/DriverTool.xcodeproj/project.pbxproj new file mode 100644 index 00000000..c5c59f00 --- /dev/null +++ b/DriverTool/DriverTool.xcodeproj/project.pbxproj @@ -0,0 +1,235 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 8DD76F9A0486AA7600D96B5E /* DriverTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* DriverTool.m */; settings = {ATTRIBUTES = (); }; }; + 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; }; + 8DD76F9F0486AA7600D96B5E /* DriverTool.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = C6859EA3029092ED04C91782 /* DriverTool.1 */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 8DD76F9E0486AA7600D96B5E /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 8; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + 8DD76F9F0486AA7600D96B5E /* DriverTool.1 in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 08FB7796FE84155DC02AAC07 /* DriverTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DriverTool.m; sourceTree = ""; }; + 08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; + 32A70AAB03705E1F00C91783 /* DriverTool_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DriverTool_Prefix.pch; sourceTree = ""; }; + 8DD76FA10486AA7600D96B5E /* DriverTool */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = DriverTool; sourceTree = BUILT_PRODUCTS_DIR; }; + C6859EA3029092ED04C91782 /* DriverTool.1 */ = {isa = PBXFileReference; lastKnownFileType = text.man; path = DriverTool.1; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8DD76F9B0486AA7600D96B5E /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 08FB7794FE84155DC02AAC07 /* DriverTool */ = { + isa = PBXGroup; + children = ( + 08FB7795FE84155DC02AAC07 /* Source */, + C6859EA2029092E104C91782 /* Documentation */, + 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */, + 1AB674ADFE9D54B511CA2CBB /* Products */, + ); + name = DriverTool; + sourceTree = ""; + }; + 08FB7795FE84155DC02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + 32A70AAB03705E1F00C91783 /* DriverTool_Prefix.pch */, + 08FB7796FE84155DC02AAC07 /* DriverTool.m */, + ); + name = Source; + sourceTree = ""; + }; + 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + 08FB779EFE84155DC02AAC07 /* Foundation.framework */, + ); + name = "External Frameworks and Libraries"; + sourceTree = ""; + }; + 1AB674ADFE9D54B511CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8DD76FA10486AA7600D96B5E /* DriverTool */, + ); + name = Products; + sourceTree = ""; + }; + C6859EA2029092E104C91782 /* Documentation */ = { + isa = PBXGroup; + children = ( + C6859EA3029092ED04C91782 /* DriverTool.1 */, + ); + name = Documentation; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8DD76F960486AA7600D96B5E /* DriverTool */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "DriverTool" */; + buildPhases = ( + 8DD76F990486AA7600D96B5E /* Sources */, + 8DD76F9B0486AA7600D96B5E /* Frameworks */, + 8DD76F9E0486AA7600D96B5E /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = DriverTool; + productInstallPath = "$(HOME)/bin"; + productName = DriverTool; + productReference = 8DD76FA10486AA7600D96B5E /* DriverTool */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 08FB7793FE84155DC02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "DriverTool" */; + compatibilityVersion = "Xcode 3.1"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 08FB7794FE84155DC02AAC07 /* DriverTool */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8DD76F960486AA7600D96B5E /* DriverTool */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 8DD76F990486AA7600D96B5E /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8DD76F9A0486AA7600D96B5E /* DriverTool.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1DEB927508733DD40010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = DriverTool_Prefix.pch; + INSTALL_PATH = /usr/local/bin; + PRODUCT_NAME = DriverTool; + }; + name = Debug; + }; + 1DEB927608733DD40010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + GCC_MODEL_TUNING = G5; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = DriverTool_Prefix.pch; + INSTALL_PATH = /usr/local/bin; + PRODUCT_NAME = DriverTool; + SDKROOT = ""; + }; + name = Release; + }; + 1DEB927908733DD40010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + CODE_SIGN_IDENTITY = "Developer ID Application: Colin Munro"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.5; + ONLY_ACTIVE_ARCH = YES; + PREBINDING = NO; + PROVISIONING_PROFILE = ""; + SDKROOT = ""; + }; + name = Debug; + }; + 1DEB927A08733DD40010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + CODE_SIGN_IDENTITY = "Developer ID Application: Colin Munro"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.5; + PREBINDING = NO; + PROVISIONING_PROFILE = ""; + SDKROOT = ""; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "DriverTool" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB927508733DD40010E9CD /* Debug */, + 1DEB927608733DD40010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "DriverTool" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB927908733DD40010E9CD /* Debug */, + 1DEB927A08733DD40010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; +} diff --git a/DriverTool/DriverTool_Prefix.pch b/DriverTool/DriverTool_Prefix.pch new file mode 100644 index 00000000..eee065ec --- /dev/null +++ b/DriverTool/DriverTool_Prefix.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the 'DriverTool' target in the 'DriverTool' project. +// + +#ifdef __OBJC__ + #import +#endif diff --git a/Feedback360/English.lproj/InfoPlist.strings b/Feedback360/English.lproj/InfoPlist.strings new file mode 100644 index 00000000..aa95ec38 --- /dev/null +++ b/Feedback360/English.lproj/InfoPlist.strings @@ -0,0 +1,4 @@ +/* Localized versions of Info.plist keys */ + +CFBundleName = "Feedback360"; +NSHumanReadableCopyright = "© Colin Munro, 2005-2011"; \ No newline at end of file diff --git a/Feedback360/Feedback360.xcodeproj/colin.mode1 b/Feedback360/Feedback360.xcodeproj/colin.mode1 new file mode 100644 index 00000000..10ad1c5f --- /dev/null +++ b/Feedback360/Feedback360.xcodeproj/colin.mode1 @@ -0,0 +1,1326 @@ + + + + + ActivePerspectiveName + Project + AllowedModules + + + BundleLoadPath + + MaxInstances + n + Module + PBXSmartGroupTreeModule + Name + Groups and Files Outline View + + + BundleLoadPath + + MaxInstances + n + Module + PBXNavigatorGroup + Name + Editor + + + BundleLoadPath + + MaxInstances + n + Module + XCTaskListModule + Name + Task List + + + BundleLoadPath + + MaxInstances + n + Module + XCDetailModule + Name + File and Smart Group Detail Viewer + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXBuildResultsModule + Name + Detailed Build Results Viewer + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXProjectFindModule + Name + Project Batch Find Tool + + + BundleLoadPath + + MaxInstances + n + Module + PBXRunSessionModule + Name + Run Log + + + BundleLoadPath + + MaxInstances + n + Module + PBXBookmarksModule + Name + Bookmarks Tool + + + BundleLoadPath + + MaxInstances + n + Module + PBXClassBrowserModule + Name + Class Browser + + + BundleLoadPath + + MaxInstances + n + Module + PBXCVSModule + Name + Source Code Control Tool + + + BundleLoadPath + + MaxInstances + n + Module + PBXDebugBreakpointsModule + Name + Debug Breakpoints Tool + + + BundleLoadPath + + MaxInstances + n + Module + XCDockableInspector + Name + Inspector + + + BundleLoadPath + + MaxInstances + n + Module + PBXOpenQuicklyModule + Name + Open Quickly Tool + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXDebugSessionModule + Name + Debugger + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXDebugCLIModule + Name + Debug Console + + + Description + DefaultDescriptionKey + DockingSystemVisible + + Extension + mode1 + FavBarConfig + + PBXProjectModuleGUID + 3B2EF59109661AF5007BFB7B + XCBarModuleItemNames + + XCBarModuleItems + + + FirstTimeWindowDisplayed + + Identifier + com.apple.perspectives.project.mode1 + MajorVersion + 31 + MinorVersion + 1 + Name + Default + Notifications + + OpenEditors + + PerspectiveWidths + + -1 + -1 + + Perspectives + + + ChosenToolbarItems + + active-target-popup + active-buildstyle-popup + action + NSToolbarFlexibleSpaceItem + buildOrClean + build-and-runOrDebug + com.apple.ide.PBXToolbarStopButton + get-info + toggle-editor + NSToolbarFlexibleSpaceItem + com.apple.pbx.toolbar.searchfield + + ControllerClassBaseName + + IconName + WindowOfProjectWithEditor + Identifier + perspective.project + IsVertical + + Layout + + + BecomeActive + + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C08E77C0454961000C914BD + 1C37FABC05509CD000000102 + 1C37FABC05539CD112110102 + E2644B35053B69B200211256 + 1C37FABC04509CD000100104 + 1CC0EA4004350EF90044410B + 1CC0EA4004350EF90041110B + + PBXProjectModuleGUID + 1CE0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + yes + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 186 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 089C166AFE841209C02AAC07 + 08FB77AFFE84173DC02AAC07 + 089C167CFE841241C02AAC07 + 3B2EF5470965B8E3007BFB7B + 089C1671FE841209C02AAC07 + 3B2EF54B0965C358007BFB7B + 0AA1909FFE8422F4C02AAC07 + 19C28FB6FE9D52B211CA2CBB + 1C37FABC05509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {186, 338}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + + XCSharingToken + com.apple.Xcode.GFSharingToken + + GeometryConfiguration + + Frame + {{0, 0}, {203, 356}} + GroupTreeTableConfiguration + + MainColumn + 186 + + RubberWindowFrame + 308 400 690 397 0 0 1280 1002 + + Module + PBXSmartGroupTreeModule + Proportion + 203pt + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CE0B20306471E060097A5F4 + PBXProjectModuleLabel + MyNewFile14.java + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1CE0B20406471E060097A5F4 + PBXProjectModuleLabel + MyNewFile14.java + + SplitCount + 1 + + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {482, 0}} + RubberWindowFrame + 308 400 690 397 0 0 1280 1002 + + Module + PBXNavigatorGroup + Proportion + 0pt + + + ContentConfiguration + + PBXProjectModuleGUID + 1CE0B20506471E060097A5F4 + PBXProjectModuleLabel + Detail + + GeometryConfiguration + + Frame + {{0, 5}, {482, 351}} + RubberWindowFrame + 308 400 690 397 0 0 1280 1002 + + Module + XCDetailModule + Proportion + 351pt + + + Proportion + 482pt + + + Name + Project + ServiceClasses + + XCModuleDock + PBXSmartGroupTreeModule + XCModuleDock + PBXNavigatorGroup + XCDetailModule + + TableOfContents + + 3BCC40840BDA915400B1619B + 1CE0B1FE06471DED0097A5F4 + 3BCC40850BDA915400B1619B + 1CE0B20306471E060097A5F4 + 1CE0B20506471E060097A5F4 + + ToolbarConfiguration + xcode.toolbar.config.default + + + ControllerClassBaseName + + IconName + WindowOfProject + Identifier + perspective.morph + IsVertical + 0 + Layout + + + BecomeActive + 1 + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C08E77C0454961000C914BD + 1C37FABC05509CD000000102 + 1C37FABC05539CD112110102 + E2644B35053B69B200211256 + 1C37FABC04509CD000100104 + 1CC0EA4004350EF90044410B + 1CC0EA4004350EF90041110B + + PBXProjectModuleGUID + 11E0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + yes + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 186 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 29B97314FDCFA39411CA2CEA + 1C37FABC05509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {186, 337}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + 1 + XCSharingToken + com.apple.Xcode.GFSharingToken + + GeometryConfiguration + + Frame + {{0, 0}, {203, 355}} + GroupTreeTableConfiguration + + MainColumn + 186 + + RubberWindowFrame + 373 269 690 397 0 0 1440 878 + + Module + PBXSmartGroupTreeModule + Proportion + 100% + + + Name + Morph + PreferredWidth + 300 + ServiceClasses + + XCModuleDock + PBXSmartGroupTreeModule + + TableOfContents + + 11E0B1FE06471DED0097A5F4 + + ToolbarConfiguration + xcode.toolbar.config.default.short + + + PerspectivesBarVisible + + ShelfIsVisible + + SourceDescription + file at '/System/Library/PrivateFrameworks/DevToolsInterface.framework/Versions/A/Resources/XCPerspectivesSpecificationMode1.xcperspec' + StatusbarIsVisible + + TimeStamp + 0.0 + ToolbarDisplayMode + 1 + ToolbarIsVisible + + ToolbarSizeMode + 1 + Type + Perspectives + UpdateMessage + The Default Workspace in this version of Xcode now includes support to hide and show the detail view (what has been referred to as the "Metro-Morph" feature). You must discard your current Default Workspace settings and update to the latest Default Workspace in order to gain this feature. Do you wish to update to the latest Workspace defaults for project '%@'? + WindowJustification + 5 + WindowOrderList + + 3B2EF5820965C4A5007BFB7B + /Users/colin/Projects2/OSX/360 Controller/Feedback360/Feedback360.xcodeproj + + WindowString + 308 400 690 397 0 0 1280 1002 + WindowTools + + + FirstTimeWindowDisplayed + + Identifier + windowTool.build + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528F0623707200166675 + PBXProjectModuleLabel + + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {500, 218}} + RubberWindowFrame + 691 470 500 500 0 0 1280 1002 + + Module + PBXNavigatorGroup + Proportion + 218pt + + + ContentConfiguration + + PBXBuildLogShowsTranscriptDefaultKey + {{0, 5}, {500, 231}} + PBXProjectModuleGUID + XCMainBuildResultsModuleGUID + PBXProjectModuleLabel + Build + XCBuildResultsTrigger_Collapse + 1021 + XCBuildResultsTrigger_Open + 1011 + + GeometryConfiguration + + Frame + {{0, 223}, {500, 236}} + RubberWindowFrame + 691 470 500 500 0 0 1280 1002 + + Module + PBXBuildResultsModule + Proportion + 236pt + + + Proportion + 459pt + + + Name + Build Results + ServiceClasses + + PBXBuildResultsModule + + StatusbarIsVisible + + TableOfContents + + 3B2EF5820965C4A5007BFB7B + 3BCC40880BDA916800B1619B + 1CD0528F0623707200166675 + XCMainBuildResultsModuleGUID + + ToolbarConfiguration + xcode.toolbar.config.build + WindowString + 691 470 500 500 0 0 1280 1002 + WindowToolGUID + 3B2EF5820965C4A5007BFB7B + WindowToolIsVisible + + + + Identifier + windowTool.debugger + Layout + + + Dock + + + ContentConfiguration + + Debugger + + HorizontalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {317, 164}} + {{317, 0}, {377, 164}} + + + VerticalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {694, 164}} + {{0, 164}, {694, 216}} + + + + LauncherConfigVersion + 8 + PBXProjectModuleGUID + 1C162984064C10D400B95A72 + PBXProjectModuleLabel + Debug - GLUTExamples (Underwater) + + GeometryConfiguration + + DebugConsoleDrawerSize + {100, 120} + DebugConsoleVisible + None + DebugConsoleWindowFrame + {{200, 200}, {500, 300}} + DebugSTDIOWindowFrame + {{200, 200}, {500, 300}} + Frame + {{0, 0}, {694, 380}} + RubberWindowFrame + 321 238 694 422 0 0 1440 878 + + Module + PBXDebugSessionModule + Proportion + 100% + + + Proportion + 100% + + + Name + Debugger + ServiceClasses + + PBXDebugSessionModule + + StatusbarIsVisible + 1 + TableOfContents + + 1CD10A99069EF8BA00B06720 + 1C0AD2AB069F1E9B00FABCE6 + 1C162984064C10D400B95A72 + 1C0AD2AC069F1E9B00FABCE6 + + ToolbarConfiguration + xcode.toolbar.config.debug + WindowString + 321 238 694 422 0 0 1440 878 + WindowToolGUID + 1CD10A99069EF8BA00B06720 + WindowToolIsVisible + 0 + + + FirstTimeWindowDisplayed + + Identifier + windowTool.find + IsVertical + + Layout + + + Dock + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CDD528C0622207200134675 + PBXProjectModuleLabel + IOHIDLib.h + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {781, 212}} + RubberWindowFrame + 31 477 781 470 0 0 1280 1002 + + Module + PBXNavigatorGroup + Proportion + 781pt + + + Proportion + 212pt + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528E0623707200166675 + PBXProjectModuleLabel + Project Find + + GeometryConfiguration + + Frame + {{0, 217}, {781, 212}} + RubberWindowFrame + 31 477 781 470 0 0 1280 1002 + + Module + PBXProjectFindModule + Proportion + 212pt + + + Proportion + 429pt + + + Name + Project Find + ServiceClasses + + PBXProjectFindModule + + StatusbarIsVisible + + TableOfContents + + 1C530D57069F1CE1000CFCEE + 3BCF4DD2097DA7030049C083 + 3BCF4DD3097DA7030049C083 + 1CDD528C0622207200134675 + 1CD0528E0623707200166675 + + WindowString + 31 477 781 470 0 0 1280 1002 + WindowToolGUID + 1C530D57069F1CE1000CFCEE + WindowToolIsVisible + + + + Identifier + MENUSEPARATOR + + + Identifier + windowTool.debuggerConsole + Layout + + + Dock + + + BecomeActive + 1 + ContentConfiguration + + PBXProjectModuleGUID + 1C78EAAC065D492600B07095 + PBXProjectModuleLabel + Debugger Console + + GeometryConfiguration + + Frame + {{0, 0}, {440, 358}} + RubberWindowFrame + 650 41 440 400 0 0 1280 1002 + + Module + PBXDebugCLIModule + Proportion + 358pt + + + Proportion + 358pt + + + Name + Debugger Console + ServiceClasses + + PBXDebugCLIModule + + StatusbarIsVisible + 1 + TableOfContents + + 1C78EAAD065D492600B07095 + 1C78EAAE065D492600B07095 + 1C78EAAC065D492600B07095 + + WindowString + 650 41 440 400 0 0 1280 1002 + + + Identifier + windowTool.run + Layout + + + Dock + + + ContentConfiguration + + LauncherConfigVersion + 3 + PBXProjectModuleGUID + 1CD0528B0623707200166675 + PBXProjectModuleLabel + Run + Runner + + HorizontalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {493, 167}} + {{0, 176}, {493, 267}} + + + VerticalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {405, 443}} + {{414, 0}, {514, 443}} + + + + + GeometryConfiguration + + Frame + {{0, 0}, {460, 159}} + RubberWindowFrame + 316 696 459 200 0 0 1280 1002 + + Module + PBXRunSessionModule + Proportion + 159pt + + + Proportion + 159pt + + + Name + Run Log + ServiceClasses + + PBXRunSessionModule + + StatusbarIsVisible + 1 + TableOfContents + + 1C0AD2B3069F1EA900FABCE6 + 1C0AD2B4069F1EA900FABCE6 + 1CD0528B0623707200166675 + 1C0AD2B5069F1EA900FABCE6 + + ToolbarConfiguration + xcode.toolbar.config.run + WindowString + 316 696 459 200 0 0 1280 1002 + WindowToolGUID + 1C0AD2B3069F1EA900FABCE6 + WindowToolIsVisible + 0 + + + Identifier + windowTool.scm + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1C78EAB2065D492600B07095 + PBXProjectModuleLabel + <No Editor> + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1C78EAB3065D492600B07095 + + SplitCount + 1 + + StatusBarVisibility + 1 + + GeometryConfiguration + + Frame + {{0, 0}, {452, 0}} + RubberWindowFrame + 743 379 452 308 0 0 1280 1002 + + Module + PBXNavigatorGroup + Proportion + 0pt + + + BecomeActive + 1 + ContentConfiguration + + PBXProjectModuleGUID + 1CD052920623707200166675 + PBXProjectModuleLabel + SCM + + GeometryConfiguration + + ConsoleFrame + {{0, 259}, {452, 0}} + Frame + {{0, 7}, {452, 259}} + RubberWindowFrame + 743 379 452 308 0 0 1280 1002 + TableConfiguration + + Status + 30 + FileName + 199 + Path + 197.09500122070312 + + TableFrame + {{0, 0}, {452, 250}} + + Module + PBXCVSModule + Proportion + 262pt + + + Proportion + 266pt + + + Name + SCM + ServiceClasses + + PBXCVSModule + + StatusbarIsVisible + 1 + TableOfContents + + 1C78EAB4065D492600B07095 + 1C78EAB5065D492600B07095 + 1C78EAB2065D492600B07095 + 1CD052920623707200166675 + + ToolbarConfiguration + xcode.toolbar.config.scm + WindowString + 743 379 452 308 0 0 1280 1002 + + + Identifier + windowTool.breakpoints + IsVertical + + Layout + + + Dock + + + BecomeActive + + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C77FABC04509CD000000102 + + PBXProjectModuleGUID + 1CE0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + no + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 168 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 1C77FABC04509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {168, 350}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + + + GeometryConfiguration + + Frame + {{0, 0}, {185, 368}} + GroupTreeTableConfiguration + + MainColumn + 168 + + RubberWindowFrame + 315 424 744 409 0 0 1440 878 + + Module + PBXSmartGroupTreeModule + Proportion + 185pt + + + ContentConfiguration + + PBXProjectModuleGUID + 1CA1AED706398EBD00589147 + PBXProjectModuleLabel + Detail + + GeometryConfiguration + + Frame + {{190, 0}, {554, 368}} + RubberWindowFrame + 315 424 744 409 0 0 1440 878 + + Module + XCDetailModule + Proportion + 554pt + + + Proportion + 368pt + + + MajorVersion + 2 + MinorVersion + 0 + Name + Breakpoints + ServiceClasses + + PBXSmartGroupTreeModule + XCDetailModule + + StatusbarIsVisible + + TableOfContents + + 1CDDB66807F98D9800BB5817 + 1CDDB66907F98D9800BB5817 + 1CE0B1FE06471DED0097A5F4 + 1CA1AED706398EBD00589147 + + ToolbarConfiguration + xcode.toolbar.config.breakpoints + WindowString + 315 424 744 409 0 0 1440 878 + WindowToolGUID + 1CDDB66807F98D9800BB5817 + WindowToolIsVisible + + + + Identifier + windowTool.debugAnimator + Layout + + + Dock + + + Module + PBXNavigatorGroup + Proportion + 100% + + + Proportion + 100% + + + Name + Debug Visualizer + ServiceClasses + + PBXNavigatorGroup + + StatusbarIsVisible + + ToolbarConfiguration + xcode.toolbar.config.debugAnimator + WindowString + 100 100 700 500 0 0 1280 1002 + + + Identifier + windowTool.bookmarks + Layout + + + Dock + + + Module + PBXBookmarksModule + Proportion + 100% + + + Proportion + 100% + + + Name + Bookmarks + ServiceClasses + + PBXBookmarksModule + + StatusbarIsVisible + 0 + WindowString + 538 42 401 187 0 0 1280 1002 + + + Identifier + windowTool.classBrowser + Layout + + + Dock + + + BecomeActive + 1 + ContentConfiguration + + OptionsSetName + Hierarchy, all classes + PBXProjectModuleGUID + 1CA6456E063B45B4001379D8 + PBXProjectModuleLabel + Class Browser - NSObject + + GeometryConfiguration + + ClassesFrame + {{0, 0}, {374, 96}} + ClassesTreeTableConfiguration + + PBXClassNameColumnIdentifier + 208 + PBXClassBookColumnIdentifier + 22 + + Frame + {{0, 0}, {630, 331}} + MembersFrame + {{0, 105}, {374, 395}} + MembersTreeTableConfiguration + + PBXMemberTypeIconColumnIdentifier + 22 + PBXMemberNameColumnIdentifier + 216 + PBXMemberTypeColumnIdentifier + 97 + PBXMemberBookColumnIdentifier + 22 + + PBXModuleWindowStatusBarHidden2 + 1 + RubberWindowFrame + 385 179 630 352 0 0 1440 878 + + Module + PBXClassBrowserModule + Proportion + 332pt + + + Proportion + 332pt + + + Name + Class Browser + ServiceClasses + + PBXClassBrowserModule + + StatusbarIsVisible + 0 + TableOfContents + + 1C0AD2AF069F1E9B00FABCE6 + 1C0AD2B0069F1E9B00FABCE6 + 1CA6456E063B45B4001379D8 + + ToolbarConfiguration + xcode.toolbar.config.classbrowser + WindowString + 385 179 630 352 0 0 1440 878 + WindowToolGUID + 1C0AD2AF069F1E9B00FABCE6 + WindowToolIsVisible + 0 + + + + diff --git a/Feedback360/Feedback360.xcodeproj/project.pbxproj b/Feedback360/Feedback360.xcodeproj/project.pbxproj new file mode 100644 index 00000000..c0138293 --- /dev/null +++ b/Feedback360/Feedback360.xcodeproj/project.pbxproj @@ -0,0 +1,285 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 3B2EF54C0965C358007BFB7B /* ForceFeedback.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B2EF54B0965C358007BFB7B /* ForceFeedback.framework */; }; + 3BBA037D09697D80008A46C9 /* emulator.c in Sources */ = {isa = PBXBuildFile; fileRef = 3BBA037C09697D80008A46C9 /* emulator.c */; }; + 3BBA03D0096A22F5008A46C9 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BBA03CF096A22F5008A46C9 /* IOKit.framework */; }; + 3BBA03E3096A29B5008A46C9 /* devlink.c in Sources */ = {isa = PBXBuildFile; fileRef = 3BBA03E2096A29B5008A46C9 /* devlink.c */; }; + 8D576312048677EA00EA77CD /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 08FB77B6FE84183AC02AAC07 /* main.c */; settings = {ATTRIBUTES = (); }; }; + 8D576314048677EA00EA77CD /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0AA1909FFE8422F4C02AAC07 /* CoreFoundation.framework */; }; + 8D5B49A804867FD3000E48DA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 8D5B49A704867FD3000E48DA /* InfoPlist.strings */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 089C167EFE841241C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + 08FB77B6FE84183AC02AAC07 /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; + 0AA1909FFE8422F4C02AAC07 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = ""; }; + 3B2EF5440965B3C7007BFB7B /* main.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = main.h; sourceTree = ""; }; + 3B2EF54B0965C358007BFB7B /* ForceFeedback.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ForceFeedback.framework; path = /System/Library/Frameworks/ForceFeedback.framework; sourceTree = ""; }; + 3BBA037B09697D80008A46C9 /* emulator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = emulator.h; sourceTree = ""; }; + 3BBA037C09697D80008A46C9 /* emulator.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = emulator.c; sourceTree = ""; }; + 3BBA03CF096A22F5008A46C9 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = ""; }; + 3BBA03E1096A29B5008A46C9 /* devlink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = devlink.h; sourceTree = ""; }; + 3BBA03E2096A29B5008A46C9 /* devlink.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = devlink.c; sourceTree = ""; }; + 8D576316048677EA00EA77CD /* Feedback360.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Feedback360.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 8D576317048677EA00EA77CD /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8D576313048677EA00EA77CD /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D576314048677EA00EA77CD /* CoreFoundation.framework in Frameworks */, + 3B2EF54C0965C358007BFB7B /* ForceFeedback.framework in Frameworks */, + 3BBA03D0096A22F5008A46C9 /* IOKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 089C166AFE841209C02AAC07 /* Feedback360 */ = { + isa = PBXGroup; + children = ( + 08FB77AFFE84173DC02AAC07 /* Source */, + 089C167CFE841241C02AAC07 /* Resources */, + 089C1671FE841209C02AAC07 /* External Frameworks and Libraries */, + 19C28FB6FE9D52B211CA2CBB /* Products */, + ); + name = Feedback360; + sourceTree = ""; + }; + 089C1671FE841209C02AAC07 /* External Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + 3BBA03CF096A22F5008A46C9 /* IOKit.framework */, + 3B2EF54B0965C358007BFB7B /* ForceFeedback.framework */, + 0AA1909FFE8422F4C02AAC07 /* CoreFoundation.framework */, + ); + name = "External Frameworks and Libraries"; + sourceTree = ""; + }; + 089C167CFE841241C02AAC07 /* Resources */ = { + isa = PBXGroup; + children = ( + 3B2EF5470965B8E3007BFB7B /* New Group */, + ); + name = Resources; + sourceTree = ""; + }; + 08FB77AFFE84173DC02AAC07 /* Source */ = { + isa = PBXGroup; + children = ( + 3B2EF5440965B3C7007BFB7B /* main.h */, + 08FB77B6FE84183AC02AAC07 /* main.c */, + 3BBA037B09697D80008A46C9 /* emulator.h */, + 3BBA037C09697D80008A46C9 /* emulator.c */, + 3BBA03E1096A29B5008A46C9 /* devlink.h */, + 3BBA03E2096A29B5008A46C9 /* devlink.c */, + ); + name = Source; + sourceTree = ""; + }; + 19C28FB6FE9D52B211CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8D576316048677EA00EA77CD /* Feedback360.bundle */, + ); + name = Products; + sourceTree = ""; + }; + 3B2EF5470965B8E3007BFB7B /* New Group */ = { + isa = PBXGroup; + children = ( + 8D576317048677EA00EA77CD /* Info.plist */, + 8D5B49A704867FD3000E48DA /* InfoPlist.strings */, + ); + name = "New Group"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8D57630D048677EA00EA77CD /* Feedback360 */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3BBDC69309793BF60023AAD8 /* Build configuration list for PBXNativeTarget "Feedback360" */; + buildPhases = ( + 8D57630F048677EA00EA77CD /* Resources */, + 8D576311048677EA00EA77CD /* Sources */, + 8D576313048677EA00EA77CD /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Feedback360; + productInstallPath = "$(HOME)/Library/Bundles"; + productName = Feedback360; + productReference = 8D576316048677EA00EA77CD /* Feedback360.bundle */; + productType = "com.apple.product-type.bundle"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 089C1669FE841209C02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 3BBDC69709793BF60023AAD8 /* Build configuration list for PBXProject "Feedback360" */; + compatibilityVersion = "Xcode 2.4"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 089C166AFE841209C02AAC07 /* Feedback360 */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8D57630D048677EA00EA77CD /* Feedback360 */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8D57630F048677EA00EA77CD /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D5B49A804867FD3000E48DA /* InfoPlist.strings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8D576311048677EA00EA77CD /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D576312048677EA00EA77CD /* main.c in Sources */, + 3BBA037D09697D80008A46C9 /* emulator.c in Sources */, + 3BBA03E3096A29B5008A46C9 /* devlink.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 8D5B49A704867FD3000E48DA /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 089C167EFE841241C02AAC07 /* English */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 3BBDC69409793BF60023AAD8 /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(HOME)/Library/Bundles"; + PRODUCT_NAME = Feedback360; + WRAPPER_EXTENSION = bundle; + ZERO_LINK = YES; + }; + name = Development; + }; + 3BBDC69509793BF60023AAD8 /* Deployment */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(HOME)/Library/Bundles"; + PRODUCT_NAME = Feedback360; + WRAPPER_EXTENSION = bundle; + ZERO_LINK = NO; + }; + name = Deployment; + }; + 3BBDC69609793BF60023AAD8 /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(HOME)/Library/Bundles"; + PRODUCT_NAME = Feedback360; + WRAPPER_EXTENSION = bundle; + }; + name = Default; + }; + 3BBDC69809793BF60023AAD8 /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "Developer ID Application: Colin Munro"; + MACOSX_DEPLOYMENT_TARGET = 10.5; + PROVISIONING_PROFILE = ""; + SDKROOT = ""; + }; + name = Development; + }; + 3BBDC69909793BF60023AAD8 /* Deployment */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + CODE_SIGN_IDENTITY = "Developer ID Application: Colin Munro"; + MACOSX_DEPLOYMENT_TARGET = 10.5; + PROVISIONING_PROFILE = ""; + SDKROOT = ""; + }; + name = Deployment; + }; + 3BBDC69A09793BF60023AAD8 /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "Developer ID Application: Colin Munro"; + MACOSX_DEPLOYMENT_TARGET = 10.5; + PROVISIONING_PROFILE = ""; + SDKROOT = ""; + }; + name = Default; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 3BBDC69309793BF60023AAD8 /* Build configuration list for PBXNativeTarget "Feedback360" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3BBDC69409793BF60023AAD8 /* Development */, + 3BBDC69509793BF60023AAD8 /* Deployment */, + 3BBDC69609793BF60023AAD8 /* Default */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Default; + }; + 3BBDC69709793BF60023AAD8 /* Build configuration list for PBXProject "Feedback360" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3BBDC69809793BF60023AAD8 /* Development */, + 3BBDC69909793BF60023AAD8 /* Deployment */, + 3BBDC69A09793BF60023AAD8 /* Default */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Default; + }; +/* End XCConfigurationList section */ + }; + rootObject = 089C1669FE841209C02AAC07 /* Project object */; +} diff --git a/Feedback360/Info.plist b/Feedback360/Info.plist new file mode 100644 index 00000000..0d8f5c19 --- /dev/null +++ b/Feedback360/Info.plist @@ -0,0 +1,40 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + com.mice.Xbox360ControllerForceFeedback + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleSignature + ???? + CFBundleVersion + 1.0 + CFPlugInDynamicRegistration + NO + CFPlugInFactories + + B8ED278F-EC8A-4E8E-B4CF-13E2A9D68E83 + Control360Factory + + CFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + + B8ED278F-EC8A-4E8E-B4CF-13E2A9D68E83 + + + CFBundleName + ${PRODUCT_NAME} + NSHumanReadableCopyright + Copyright © 2013 MICE Software. All rights reserved. + + diff --git a/Feedback360/devlink.c b/Feedback360/devlink.c new file mode 100644 index 00000000..d6a1e9d3 --- /dev/null +++ b/Feedback360/devlink.c @@ -0,0 +1,62 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + devlink.c - code to speak to the driver itself + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include +#include "devlink.h" + +// Initialise the link +bool Device_Initialise(DeviceLink *link,io_object_t device) +{ + IOCFPlugInInterface **plugInInterface; + SInt32 score; + IOReturn ret; + + plugInInterface=NULL; + score=0; + ret=IOCreatePlugInInterfaceForService(device,kIOHIDDeviceUserClientTypeID,kIOCFPlugInInterfaceID,&plugInInterface,&score); + if(ret!=kIOReturnSuccess) return FALSE; + ret=(*plugInInterface)->QueryInterface(plugInInterface,CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID121),(LPVOID)&link->interface); + (*plugInInterface)->Release(plugInInterface); + if(ret!=kIOReturnSuccess) return FALSE; + (*link->interface)->open(link->interface,0); + return TRUE; +} + +// Finish the link +void Device_Finalise(DeviceLink *link) +{ + (*link->interface)->close(link->interface); + (*link->interface)->Release(link->interface); + link->interface=NULL; +} + +// Send a report via the link +bool Device_Send(DeviceLink *link,void *data,int length) +{ + if(link->interface==NULL) return FALSE; + else { + IOReturn res=(*link->interface)->setReport(link->interface,kIOHIDReportTypeOutput,0,data,length,10000,NULL,NULL,NULL); + if (res != kIOReturnSuccess) + fprintf(stderr, "Device_Send failed: 0x%.8x\n", res); + return res==kIOReturnSuccess; + } +} diff --git a/Feedback360/devlink.h b/Feedback360/devlink.h new file mode 100644 index 00000000..fadaf901 --- /dev/null +++ b/Feedback360/devlink.h @@ -0,0 +1,33 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + devlink.h - Interface to the device link + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include +#include + +typedef struct { + IOHIDDeviceInterface121 **interface; +} DeviceLink; + +bool Device_Initialise(DeviceLink *link,io_object_t device); +void Device_Finalise(DeviceLink *link); + +bool Device_Send(DeviceLink *link,void *data,int length); diff --git a/Feedback360/emulator.c b/Feedback360/emulator.c new file mode 100644 index 00000000..5d676754 --- /dev/null +++ b/Feedback360/emulator.c @@ -0,0 +1,343 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + emulator.c - simulate a force feedback device + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "emulator.h" + +/* + * This code could do with being improved. For example, the two motors could + * allow for a "left" and "right" rumble in a car game. + * + * For debugging, you may use fprintf(stderr,...). The output will appear on + * the console of whatever game is using the Apple Force Feedback Framework. + */ + +#define LoopGranularity 500 // Microseconds +#define LoopTimerDelay (LoopGranularity*0.000001f) // In seconds + +static void Emulate_Timer(CFRunLoopTimerRef timer,void *context); + +// Initialise the emulation of a force feedback device +void Emulate_Initialise(ForceEmulator *emulator,int effectCount,void (*SetForce)(void*,unsigned char,unsigned char),void *context) +{ + int i; + CFRunLoopTimerContext callbackData; + + // Set callback + emulator->SetForce=SetForce; + emulator->context=context; + // Create effects memory + emulator->effects=(ForceEffect*)malloc(sizeof(ForceEffect)*effectCount); + emulator->effectCount=effectCount; + // Defaults + emulator->enable=TRUE; + emulator->pause=FALSE; + emulator->gain=4; + emulator->maxGain=4; + emulator->activeEffect=-1; + // Reset + for(i=0;ieffects[i].inUse=FALSE; + // Launch timer + callbackData.version=0; + callbackData.info=emulator; + callbackData.retain=NULL; + callbackData.release=NULL; + callbackData.copyDescription=NULL; + emulator->timer=CFRunLoopTimerCreate(NULL,LoopTimerDelay,LoopTimerDelay,0,0,Emulate_Timer,&callbackData); + CFRunLoopAddTimer(CFRunLoopGetCurrent(),emulator->timer,kCFRunLoopCommonModes); +} + +// Close down the force feedback stuff +void Emulate_Finalise(ForceEmulator *emulator) +{ + CFRunLoopTimerInvalidate(emulator->timer); + CFRelease(emulator->timer); + free(emulator->effects); + emulator->SetForce(emulator->context,0,0); +} + +// Call the callback, if output is enabled +void Emulate_Callback(ForceEmulator *emulator,unsigned char large,unsigned char small) +{ + emulator->oldLarge=large; + emulator->oldSmall=small; + if(emulator->enable) emulator->SetForce(emulator->context,large,small); +} + +// Create an effect - for the FF API +int Emulate_CreateEffect(ForceEmulator *emulator,const ForceParams *params) +{ + int i; + + for(i=0;ieffectCount;i++) { + if(!emulator->effects[i].inUse) { + emulator->effects[i].inUse=TRUE; + if(!Emulate_ChangeEffect(emulator,i+1,params)) { + emulator->effects[i].inUse=FALSE; + return 0; + } + return i+1; + } + } + return 0; +} + +// Change an effect - for the FF API +bool Emulate_ChangeEffect(ForceEmulator *emulator,int index,const ForceParams *params) +{ + ForceEffect *effect=emulator->effects+index-1; + effect->gain=params->gain; + effect->maxLevel=params->maxLevel; + effect->startCount=params->startDelay/LoopGranularity; + effect->attackLevel=params->attackLevel; + effect->attackCount=params->attackTime/LoopGranularity; + effect->sustainLevel=params->sustainLevel; + effect->sustainCount=params->sustainTime/LoopGranularity; + effect->fadeLevel=params->fadeLevel; + effect->fadeCount=params->fadeTime/LoopGranularity; + return TRUE; +} + +// Destroy an effect - for the FF API +void Emulate_DestroyEffect(ForceEmulator *emulator,int index) +{ + emulator->effects[index-1].inUse=FALSE; + if(emulator->activeEffect==(index-1)) emulator->activeEffect=-1; +} + +// Returns true if the effect index is in use +bool Emulate_IsValidEffect(ForceEmulator *emulator,int index) +{ + if((index<1)||(index>emulator->effectCount)) return FALSE; + return emulator->effects[index-1].inUse; +} + +// Returns true if the effect index is playing +bool Emulate_IsPlaying(ForceEmulator *emulator,int index) +{ + return emulator->activeEffect==(index-1); +} + +// Returns true if the device has no effects +bool Emulate_IsEmpty(ForceEmulator *emulator) +{ + int i; + + for(i=0;ieffectCount;i++) + if(emulator->effects[i].inUse) + return FALSE; + return TRUE; +} + +// Resets the device +void Emulate_Reset(ForceEmulator *emulator) +{ + int i; + + for(i=0;ieffectCount;i++) emulator->effects[i].inUse=FALSE; + Emulate_Callback(emulator,0,0); +} + +// Starts an effect for the specified number of loops +void Emulate_Start(ForceEmulator *emulator,int index,int iterations) +{ + ForceEffect *effect; + +// fprintf(stderr,"Emulate_Start(%p,%i,%i)\n",emulator,index,iterations); + effect=emulator->effects+index-1; + effect->countStart=effect->startCount; + effect->countAttack=effect->attackCount; + effect->countSustain=effect->sustainCount; + effect->countFade=effect->fadeCount; + effect->countLoop=iterations; + emulator->activeEffect=index-1; +} + +// Stops an effect +void Emulate_Stop(ForceEmulator *emulator,int index) +{ +// fprintf(stderr,"Emulate_Stop(%p,%i)\n",emulator,index); + if((index-1)==emulator->activeEffect) { + emulator->activeEffect=-1; + Emulate_Callback(emulator,0,0); + } +} + +// Returns true if no effects are running +bool Emulate_IsStopped(ForceEmulator *emulator) +{ + return emulator->activeEffect==-1; +} + +// Returns the number of used effects +UInt32 Emulate_Effects_Used(ForceEmulator *emulator) +{ + int i,j; + + for(i=j=0;ieffectCount;i++) + if(emulator->effects[i].inUse) + j++; + return j; +} + +// Returns the number of possible effects +UInt32 Emulate_Effects_Total(ForceEmulator *emulator) +{ + return emulator->effectCount; +} + +// Enables or disables the force feedback +void Emulate_SetEnable(ForceEmulator *emulator,bool enable) +{ + bool old=emulator->enable; + // Stop motors in case they were running + if(old&&(!enable)) Emulate_Callback(emulator,0,0); + emulator->enable=enable; + // Resume motors at last computed value, as we'll have + // been computing new values for them even if disabled + if((!old)&&enable) Emulate_Callback(emulator,emulator->oldLarge,emulator->oldSmall); +} + +// Returns true if enabled +bool Emulate_IsEnabled(ForceEmulator *emulator) +{ + return emulator->enable; +} + +// Pauses the device +void Emulate_SetPaused(ForceEmulator *emulator,bool enable) +{ + bool old=emulator->pause; + // Stop motors in case they were running + if((!old)&&enable) Emulate_Callback(emulator,0,0); + emulator->pause=enable; + // Resume motors at last computed value, as we'll be + // resuming feedback effects where we left off. + if(old&&(!enable)) Emulate_Callback(emulator,emulator->oldLarge,emulator->oldSmall); +} + +// Returns true if paused +bool Emulate_IsPaused(ForceEmulator *emulator) +{ + return emulator->pause; +} + +// Sets the gain for the device +void Emulate_SetGain(ForceEmulator *emulator,int gain,int gainMax) +{ + if((emulator->gain<=0)||(emulator->maxGain<=0)) return; + emulator->gain=gain; + emulator->maxGain=gainMax; + while(emulator->maxGain<4) { + emulator->gain*=2; + emulator->maxGain*=2; + } +} + +// Utility - scales a value +static inline int Emulate_Scale(int from,int to,int max,int val) +{ + int upper=max-1; + return from+(((to-from)*(upper-val))/upper); +} + +// Utility - computes the values for the large and small motors from the effect +static void Emulate_Force(ForceEmulator *emulator,int force,int maxGain) +{ + int adjusted; + int bling; + int small,large; + +// fprintf(stderr,"Emulate_Force(%p,%i)\n",emulator,force); + adjusted=(force*emulator->gain)/emulator->maxGain; + bling=maxGain/4; + if(adjustedactiveEffect; + if((i==-1)||emulator->pause) return; + effect=emulator->effects+emulator->activeEffect; + // Process each counter on the effect, to see what's happening + if(effect->countStart>0) { + // In the start (pre-effect) stage + level=effect->attackLevel; + effect->countStart--; + } else { + if(effect->countAttack>0) { + // In the attack stage + level=Emulate_Scale(effect->attackLevel,effect->sustainLevel,effect->attackCount,effect->countAttack); + effect->countAttack--; + } else { + if(effect->countSustain>0) { + // In the sustain stage + level=effect->sustainLevel; + effect->countSustain--; + } else { + if(effect->countFade>0) { + // In the fade stage + level=Emulate_Scale(effect->sustainLevel,effect->fadeLevel,effect->fadeCount,effect->countFade); + effect->countFade--; + } else { + // Work out if we need to do it again + effect->countLoop--; + if(effect->countLoop>0) { + // Prepare for next loop + level=effect->attackLevel; + effect->countStart=effect->startCount; + effect->countAttack=effect->attackCount; + effect->countSustain=effect->sustainCount; + effect->countFade=effect->fadeCount; + } else { + // Effect finished + level=0; + emulator->activeEffect=-1; + } + } + } + } + } + // Actually calculate what to do for the effect + Emulate_Force(emulator,(level*effect->gain)/effect->maxLevel,effect->maxLevel); +} diff --git a/Feedback360/emulator.h b/Feedback360/emulator.h new file mode 100644 index 00000000..5c209989 --- /dev/null +++ b/Feedback360/emulator.h @@ -0,0 +1,112 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + emulator.h - Interface to fake FF API effects using rumble motors + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include + +typedef enum { + fsStop, + fsPlay, +} ForceState; + +typedef struct { + bool inUse; + ForceState state; + // Information + int gain; + int maxLevel; + int startCount; + int attackLevel; + int attackCount; + int sustainLevel; + int sustainCount; + int fadeLevel; + int fadeCount; + // Runtime + int countStart; + int countAttack; + int countSustain; + int countFade; + int countLoop; +} ForceEffect; + +typedef struct { + // Settings + int gain; // 0-maxLevel + int maxLevel; + int startDelay; // Microseconds + // Envelope for effect + int attackLevel; // 0-maxLevel + int attackTime; // Microseconds + int sustainLevel; // 0-maxLevel + int sustainTime; // Microseconds + int fadeLevel; // 0-maxLevel + int fadeTime; // Microseconds +} ForceParams; + +typedef struct { + // Callback + void (*SetForce)(void *context,unsigned char large,unsigned char small); + void *context; + // Options + int gain,maxGain; + bool enable,pause; + // Effect entries + ForceEffect *effects; + int effectCount; + // Runtime + CFRunLoopTimerRef timer; + unsigned char oldLarge,oldSmall; + int activeEffect; +} ForceEmulator; + +// Constructor/destructor +void Emulate_Initialise(ForceEmulator *emulator,int effectCount,void (*SetForce)(void*,unsigned char,unsigned char),void *context); +void Emulate_Finalise(ForceEmulator *emulator); + +// Options +void Emulate_SetGain(ForceEmulator *emulator,int gain,int gainMax); +void Emulate_SetEnable(ForceEmulator *emulator,bool enable); +bool Emulate_IsEnabled(ForceEmulator *emulator); +void Emulate_SetPaused(ForceEmulator *emulator,bool enable); +bool Emulate_IsPaused(ForceEmulator *emulator); + +// Using effects +int Emulate_CreateEffect(ForceEmulator *emulator,const ForceParams *params); +bool Emulate_ChangeEffect(ForceEmulator *emulator,int index,const ForceParams *params); +void Emulate_DestroyEffect(ForceEmulator *emulator,int index); + +bool Emulate_IsValidEffect(ForceEmulator *emulator,int index); +bool Emulate_IsPlaying(ForceEmulator *emulator,int index); + +bool Emulate_IsEmpty(ForceEmulator *emulator); + +void Emulate_Reset(ForceEmulator *emulator); + +void Emulate_Start(ForceEmulator *emulator,int index,int iterations); +void Emulate_Stop(ForceEmulator *emulator,int index); +bool Emulate_IsStopped(ForceEmulator *emulator); + +UInt32 Emulate_Effects_Used(ForceEmulator *emulator); +UInt32 Emulate_Effects_Total(ForceEmulator *emulator); + +// Callbacks +void Emulate_Callback(ForceEmulator *emulator,unsigned char large,unsigned char small); diff --git a/Feedback360/main.c b/Feedback360/main.c new file mode 100644 index 00000000..b4917c1a --- /dev/null +++ b/Feedback360/main.c @@ -0,0 +1,447 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + main.c - Main code for the FF plugin + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include +#include "main.h" + +static void dealloc360Feedback(Xbox360ForceFeedback *this); + +// IUnknown + +static HRESULT Feedback360QueryInterface(void *that,REFIID iid,LPVOID *ppv) +{ + Xbox360ForceFeedback *this=FFThis(that); + CFUUIDRef interface; + + interface=CFUUIDCreateFromUUIDBytes(NULL,iid); + // IOForceFeedbackDevice + if(CFEqual(interface,kIOForceFeedbackDeviceInterfaceID)) + *ppv=&this->iIOForceFeedbackDeviceInterface; + // IUnknown || IOCFPlugInInterface + else if(CFEqual(interface,IUnknownUUID)||CFEqual(interface,kIOCFPlugInInterfaceID)) + *ppv=&this->iIOCFPlugInInterface; + else + *ppv=NULL; + // Done + CFRelease(interface); + if((*ppv)==NULL) return E_NOINTERFACE; + else { + this->iIOCFPlugInInterface.pseudoVTable->AddRef(*ppv); + return S_OK; + } +} + +static ULONG Feedback360AddRef(void *that) +{ + Xbox360ForceFeedback *this=FFThis(that); + this->refCount++; + return this->refCount; +} + +static ULONG Feedback360Release(void *that) +{ + Xbox360ForceFeedback *this=FFThis(that); + this->refCount--; + if(this->refCount==0) { + dealloc360Feedback(this); + return 0; + } else return this->refCount; +} + +// IOCFPlugInInterface + +static IOReturn Feedback360Probe(void *that,CFDictionaryRef propertyTable,io_service_t service,SInt32 *order) +{ + if ((service==0) + || ((!IOObjectConformsTo(service,"Xbox360ControllerClass")) + && (!IOObjectConformsTo(service,"Wireless360Controller")))) return kIOReturnBadArgument; + return S_OK; +} + +static IOReturn Feedback360Start(void *that,CFDictionaryRef propertyTable,io_service_t service) +{ + return S_OK; +} + +static IOReturn Feedback360Stop(void *that) +{ + return S_OK; +} + +// IOForceFeedbackDevice + +static HRESULT Feedback360GetVersion(void *this,ForceFeedbackVersion *version) +{ + if((this==NULL)||(version==NULL)) return FFERR_INVALIDPARAM; + version->apiVersion.majorRev=kFFPlugInAPIMajorRev; + version->apiVersion.minorAndBugRev=kFFPlugInAPIMinorAndBugRev; + version->apiVersion.stage=kFFPlugInAPIStage; + version->apiVersion.nonRelRev=kFFPlugInAPINonRelRev; + version->plugInVersion.majorRev=FeedbackDriverVersionMajor; + version->plugInVersion.minorAndBugRev=FeedbackDriverVersionMinor; + version->plugInVersion.stage=FeedbackDriverVersionStage; + version->plugInVersion.nonRelRev=FeedbackDriverVersionNonRelRev; + return S_OK; +} + +static void Feedback360_Callback(void *that,unsigned char large,unsigned char small) +{ + Xbox360ForceFeedback *this=(Xbox360ForceFeedback*)that; + char buf[]={0x00,0x04,large,small}; + if(!this->manual) Device_Send(&this->device,buf,sizeof(buf)); +} + +static HRESULT Feedback360InitializeTerminate(void *that,NumVersion APIversion,io_object_t hidDevice,boolean_t begin) +{ + Xbox360ForceFeedback *this=FFThis(that); +// fprintf(stderr,"Feedback360InitializeTerminate(%p,[%i.%i.%i.%i],%p,%s)\n",this,APIversion.majorRev,APIversion.minorAndBugRev,APIversion.stage,APIversion.nonRelRev,hidDevice,begin?"true":"false"); + if(this==NULL) return FFERR_INVALIDPARAM; + if(begin) { +// fprintf(stderr,"Feedback: Initialising...\n"); + // Initialize + if(APIversion.majorRev!=kFFPlugInAPIMajorRev) + { +// fprintf(stderr,"Feedback: Invalid version\n"); + return FFERR_INVALIDPARAM; + } + // From probe + if( (hidDevice==0) + || ((!IOObjectConformsTo(hidDevice,"Xbox360ControllerClass")) + && (!IOObjectConformsTo(hidDevice,"Wireless360Controller"))) ) + { +// fprintf(stderr,"Feedback: Invalid device\n"); + return FFERR_INVALIDPARAM; + } + Emulate_Initialise(&this->emulator,10,Feedback360_Callback,this); + if(!Device_Initialise(&this->device,hidDevice)) { +// fprintf(stderr,"Feedback: Failed to initialise\n"); + Emulate_Finalise(&this->emulator); + return FFERR_NOINTERFACE; + } + this->manual=FALSE; + } else { +// fprintf(stderr,"Feedback: Terminating\n"); + // Terminate + Emulate_Finalise(&this->emulator); + Device_Finalise(&this->device); + } + return FF_OK; +} + +static HRESULT Feedback360DestroyEffect(void *that,FFEffectDownloadID downloadID) +{ + Xbox360ForceFeedback *this=FFThis(that); + Emulate_DestroyEffect(&this->emulator,downloadID); + return FF_OK; +} + +static bool Feedback360SupportedEffect(CFUUIDRef effect) +{ + if(CFEqual(effect,kFFEffectType_SawtoothDown_ID)) return TRUE; + if(CFEqual(effect,kFFEffectType_SawtoothUp_ID)) return TRUE; + if(CFEqual(effect,kFFEffectType_Sine_ID)) return TRUE; + if(CFEqual(effect,kFFEffectType_Spring_ID)) return TRUE; + if(CFEqual(effect,kFFEffectType_Square_ID)) return TRUE; + if(CFEqual(effect,kFFEffectType_Triangle_ID)) return TRUE; + return FALSE; +} + +static bool Feedback360ConvertEffect(const FFEFFECT *effect,ForceParams *params) +{ + if((effect->cbTypeSpecificParams!=sizeof(FFPERIODIC))||(effect->lpvTypeSpecificParams==NULL)) return FALSE; + // Settings + params->startDelay=effect->dwStartDelay; + params->gain=effect->dwGain; + params->maxLevel=10000; + // Envelope + params->sustainLevel=((FFPERIODIC*)effect->lpvTypeSpecificParams)->dwMagnitude; + // Documentation was a bit confusing here as to which value was right, compared to what a game actually used +// params->sustainTime=effect->dwDuration; + params->sustainTime=((FFPERIODIC*)effect->lpvTypeSpecificParams)->dwPeriod; + if(effect->lpEnvelope==NULL) { + params->attackLevel=params->sustainLevel; + params->attackTime=0; + params->fadeLevel=params->sustainLevel; + params->fadeTime=0; + } else { + if(effect->lpEnvelope->dwSizeattackLevel=effect->lpEnvelope->dwAttackLevel; + params->attackTime=effect->lpEnvelope->dwAttackTime; + params->fadeLevel=effect->lpEnvelope->dwFadeLevel; + params->fadeTime=effect->lpEnvelope->dwFadeTime; + } + // Done + return TRUE; +} + +static HRESULT Feedback360DownloadEffect(void *that,CFUUIDRef effectType,FFEffectDownloadID *downloadID,FFEFFECT *effect,FFEffectParameterFlag flags) +{ + ForceParams params; + Xbox360ForceFeedback *this=FFThis(that); + + if(!Feedback360SupportedEffect(effectType)) return FFERR_UNSUPPORTED; + if(!(effect->dwFlags&FFEFF_SPHERICAL)) return FFERR_UNSUPPORTED; + if(effect->dwTriggerButton!=FFEB_NOTRIGGER) return FFERR_UNSUPPORTED; + if(!Feedback360ConvertEffect(effect,¶ms)) return FFERR_UNSUPPORTED; + if(Emulate_IsPaused(&this->emulator)) return FFERR_DEVICEPAUSED; + if(flags&FFEP_NODOWNLOAD) return FF_OK; + if((*downloadID)==0) { + *downloadID=Emulate_CreateEffect(&this->emulator,¶ms); + if((*downloadID)==0) return FFERR_DEVICEFULL; + } else { + if(!Emulate_IsValidEffect(&this->emulator,*downloadID)) return FFERR_INVALIDDOWNLOADID; + if(!Emulate_ChangeEffect(&this->emulator,*downloadID,¶ms)) return FFERR_EFFECTTYPEMISMATCH; + } + if(flags&FFEP_START) { + // Restart + } + return FF_OK; +} + +static HRESULT Feedback360Escape(void *that,FFEffectDownloadID downloadID,FFEFFESCAPE *escape) +{ + Xbox360ForceFeedback *this=FFThis(that); + + if(this==NULL) return FFERR_INVALIDPARAM; + if(downloadID!=0) return FFERR_UNSUPPORTED; + if(escape->dwSizecbOutBuffer=0; + switch(escape->dwCommand) { + case 0x00: // Control motors + if(escape->cbInBuffer!=1) return FFERR_INVALIDPARAM; + this->manual=((unsigned char*)escape->lpvInBuffer)[0]!=0x00; + break; + case 0x01: // Set motors + if(escape->cbInBuffer!=2) return FFERR_INVALIDPARAM; + if(this->manual) { + unsigned char *data=escape->lpvInBuffer; + unsigned char buf[]={0x00,0x04,data[0],data[1]}; + Device_Send(&this->device,buf,sizeof(buf)); + } + break; + case 0x02: // Set LED + if(escape->cbInBuffer!=1) return FFERR_INVALIDPARAM; + { + unsigned char *data=escape->lpvInBuffer; + unsigned char buf[]={0x01,0x03,data[0]}; + Device_Send(&this->device,buf,sizeof(buf)); + } + break; + case 0x03: // Power off + { + unsigned char buf[] = {0x02, 0x02}; + Device_Send(&this->device, buf, sizeof(buf)); + } + break; + default: + fprintf(stderr, "Xbox360Controller FF plugin: Unknown escape (%i)\n", (int)escape->dwCommand); + return FFERR_UNSUPPORTED; + } + return FF_OK; +} + +static HRESULT Feedback360GetEffectStatus(void *that,FFEffectDownloadID downloadID,FFEffectStatusFlag *statusCode) +{ + Xbox360ForceFeedback *this=FFThis(that); + + if(!Emulate_IsValidEffect(&this->emulator,downloadID)) return FFERR_INVALIDDOWNLOADID; + *statusCode=Emulate_IsPlaying(&this->emulator,downloadID)?FFEGES_PLAYING:FFEGES_NOTPLAYING; + return FF_OK; +} + +static HRESULT Feedback360GetForceFeedbackCapabilities(void *this,FFCAPABILITIES *capabilities) +{ + capabilities->ffSpecVer.majorRev=kFFPlugInAPIMajorRev; + capabilities->ffSpecVer.minorAndBugRev=kFFPlugInAPIMinorAndBugRev; + capabilities->ffSpecVer.stage=kFFPlugInAPIStage; + capabilities->ffSpecVer.nonRelRev=kFFPlugInAPINonRelRev; + capabilities->supportedEffects=FFCAP_ET_SQUARE|FFCAP_ET_SINE|FFCAP_ET_TRIANGLE|FFCAP_ET_SAWTOOTHUP|FFCAP_ET_SAWTOOTHDOWN; + capabilities->emulatedEffects=0; + capabilities->subType=FFCAP_ST_VIBRATION; + capabilities->numFfAxes=1; + capabilities->ffAxes[0]=FFJOFS_X; + capabilities->storageCapacity=256; + capabilities->playbackCapacity=1; + capabilities->driverVer.majorRev=FeedbackDriverVersionMajor; + capabilities->driverVer.minorAndBugRev=FeedbackDriverVersionMinor; + capabilities->driverVer.stage=FeedbackDriverVersionStage; + capabilities->driverVer.nonRelRev=FeedbackDriverVersionNonRelRev; + capabilities->firmwareVer.majorRev=1; + capabilities->firmwareVer.minorAndBugRev=0; + capabilities->firmwareVer.stage=developStage; + capabilities->firmwareVer.nonRelRev=0; + capabilities->hardwareVer.majorRev=1; + capabilities->hardwareVer.minorAndBugRev=0; + capabilities->hardwareVer.stage=developStage; + capabilities->hardwareVer.nonRelRev=0; + return S_OK; +} + +static HRESULT Feedback360GetForceFeedbackState(void *that,ForceFeedbackDeviceState *deviceState) +{ + Xbox360ForceFeedback *this=FFThis(that); + + if(deviceState->dwSizedwSize=sizeof(ForceFeedbackDeviceState); + deviceState->dwState + = Emulate_IsEmpty(&this->emulator)?FFGFFS_EMPTY:0 + | Emulate_IsStopped(&this->emulator)?FFGFFS_STOPPED:0 + | Emulate_IsPaused(&this->emulator)?FFGFFS_PAUSED:0 + | Emulate_IsEnabled(&this->emulator)?FFGFFS_ACTUATORSON:FFGFFS_ACTUATORSOFF; + deviceState->dwLoad=(Emulate_Effects_Used(&this->emulator)*100)/Emulate_Effects_Total(&this->emulator); + return S_OK; +} + +static HRESULT Feedback360SendForceFeedbackCommand(void *that,FFCommandFlag state) +{ + Xbox360ForceFeedback *this=FFThis(that); + + switch(state) { + case FFSFFC_RESET: + Emulate_Reset(&this->emulator); + return S_OK; + case FFSFFC_STOPALL: + Emulate_Stop(&this->emulator,0); // 0 == all effects + return S_OK; + case FFSFFC_PAUSE: + case FFSFFC_CONTINUE: + Emulate_SetPaused(&this->emulator,state==FFSFFC_PAUSE); + return S_OK; + case FFSFFC_SETACTUATORSON: + case FFSFFC_SETACTUATORSOFF: + Emulate_SetEnable(&this->emulator,state==FFSFFC_SETACTUATORSON); + return S_OK; + default: + return FFERR_UNSUPPORTED; + } +} + +static HRESULT Feedback360SetProperty(void *that,FFProperty property,void *value) +{ + Xbox360ForceFeedback *this=FFThis(that); + + switch(property) { + case FFPROP_FFGAIN: + { + UInt32 uValue = *((UInt32*)value); + if (uValue > 10000) + return FFERR_INVALIDPARAM; + Emulate_SetGain(&this->emulator, uValue, 10000); + } + return FF_OK; + default: + return FFERR_UNSUPPORTED; + } +} + +static HRESULT Feedback360StartEffect(void *that,FFEffectDownloadID downloadID,FFEffectStartFlag mode,UInt32 iterations) +{ + Xbox360ForceFeedback *this=FFThis(that); + + if(mode&FFES_SOLO) Feedback360SendForceFeedbackCommand(that,FFSFFC_RESET); + Emulate_Start(&this->emulator,downloadID,iterations); + return S_OK; +} + +static HRESULT Feedback360StopEffect(void *that,FFEffectDownloadID downloadID) +{ + Xbox360ForceFeedback *this=FFThis(that); + + if(!Emulate_IsValidEffect(&this->emulator,downloadID)) return FFERR_INVALIDDOWNLOADID; + Emulate_Stop(&this->emulator,downloadID); + return S_OK; +} + +// Function table + +static IOCFPlugInInterface functionMap360_IOCFPlugInInterface={ + // Padding required for COM + NULL, + // IUnknown + Feedback360QueryInterface, + Feedback360AddRef, + Feedback360Release, + // IOCFPlugInInterface + 1,0, // Version + Feedback360Probe, + Feedback360Start, + Feedback360Stop +}; + +static IOForceFeedbackDeviceInterface functionMap360_IOForceFeedbackDeviceInterface={ + // Padding required for COM + NULL, + // IUnknown + Feedback360QueryInterface, + Feedback360AddRef, + Feedback360Release, + // IOForceFeedbackDevice + Feedback360GetVersion, + Feedback360InitializeTerminate, + Feedback360DestroyEffect, + Feedback360DownloadEffect, + Feedback360Escape, + Feedback360GetEffectStatus, + Feedback360GetForceFeedbackCapabilities, + Feedback360GetForceFeedbackState, + Feedback360SendForceFeedbackCommand, + Feedback360SetProperty, + Feedback360StartEffect, + Feedback360StopEffect +}; + +// Constructor and destructor + +static IOCFPlugInInterface** alloc360Feedback(CFUUIDRef uuid) +{ + Xbox360ForceFeedback *item; + + item=(Xbox360ForceFeedback*)malloc(sizeof(Xbox360ForceFeedback)); + item->iIOCFPlugInInterface.pseudoVTable=(IUnknownVTbl*)&functionMap360_IOCFPlugInInterface; + item->iIOCFPlugInInterface.obj=item; + item->iIOForceFeedbackDeviceInterface.pseudoVTable=(IUnknownVTbl*)&functionMap360_IOForceFeedbackDeviceInterface; + item->iIOForceFeedbackDeviceInterface.obj=item; + item->factoryID=CFRetain(uuid); + CFPlugInAddInstanceForFactory(uuid); + item->refCount=1; + return (IOCFPlugInInterface**)&item->iIOCFPlugInInterface.pseudoVTable; +} + +static void dealloc360Feedback(Xbox360ForceFeedback *this) +{ + CFUUIDRef uuid; + + uuid=this->factoryID; + free(this); + if(uuid) { + CFPlugInRemoveInstanceForFactory(uuid); + CFRelease(uuid); + } +} + +// External factory function + +void* Control360Factory(CFAllocatorRef allocator,CFUUIDRef uuid) +{ + if(CFEqual(uuid,kIOForceFeedbackLibTypeID)) return (void*)alloc360Feedback(uuid); + else return NULL; +} diff --git a/Feedback360/main.h b/Feedback360/main.h new file mode 100644 index 00000000..7da07086 --- /dev/null +++ b/Feedback360/main.h @@ -0,0 +1,58 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + main.h - defines the structure used for the plugin COM object + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include +#include +#include "emulator.h" +#include "devlink.h" + +struct _Xbox360ForceFeedback; + +typedef struct _Xbox360InterfaceMap { + IUnknownVTbl *pseudoVTable; + struct _Xbox360ForceFeedback *obj; +} Xbox360InterfaceMap; + +typedef struct _Xbox360ForceFeedback { + Xbox360InterfaceMap iIOCFPlugInInterface; + Xbox360InterfaceMap iIOForceFeedbackDeviceInterface; + CFUUIDRef factoryID; + UInt32 refCount; + ForceEmulator emulator; + DeviceLink device; + bool manual; +} Xbox360ForceFeedback; + +#define FFThis(interface) (((interface)==NULL)?NULL:(((Xbox360InterfaceMap*)(interface))->obj)) + +#define FeedbackDriverVersionMajor 1 +#define FeedbackDriverVersionMinor 0 +#define FeedbackDriverVersionStage developStage +#define FeedbackDriverVersionNonRelRev 0 + +// B8ED278F-EC8A-4E8E-B4CF-13E2A9D68E83 +#define FeedbackDriverUuid CFUUIDGetConstantUUIDWithBytes(NULL, \ + 0xB8, 0xED, 0x27, 0x8F, 0xEC, 0x8A, 0x4E, 0x8E, \ + 0xB4, 0xCF, 0x13, 0xE2, 0xA9, 0xD6, 0x8E, 0x83) + +// Factory function +void* Control360Factory(CFAllocatorRef allocator,CFUUIDRef uuid); diff --git a/Feedback360/version.plist b/Feedback360/version.plist new file mode 100644 index 00000000..53bf3a3f --- /dev/null +++ b/Feedback360/version.plist @@ -0,0 +1,16 @@ + + + + + BuildVersion + 12 + CFBundleVersion + 1.0 + ProductBuildVersion + 7K571 + ProjectName + DevToolsWizardTemplates + SourceVersion + 3870000 + + diff --git a/Install360Controller/Install360Controller.pkgproj b/Install360Controller/Install360Controller.pkgproj new file mode 100755 index 00000000..be4569ff --- /dev/null +++ b/Install360Controller/Install360Controller.pkgproj @@ -0,0 +1,1065 @@ + + + + + PACKAGES + + + PACKAGE_FILES + + DEFAULT_INSTALL_LOCATION + / + HIERARCHY + + CHILDREN + + + CHILDREN + + + CHILDREN + + GID + 80 + PATH + Utilities + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + GID + 80 + PATH + Applications + PATH_TYPE + 0 + PERMISSIONS + 509 + TYPE + 1 + UID + 0 + + + CHILDREN + + + CHILDREN + + + CHILDREN + + + CHILDREN + + + CHILDREN + + GID + 80 + PATH + ../360Daemon/build/Release/360Daemon + PATH_TYPE + 1 + PERMISSIONS + 493 + TYPE + 3 + UID + 0 + + + CHILDREN + + + CHILDREN + + GID + 80 + PATH + ../360Daemon/Alert.tif + PATH_TYPE + 1 + PERMISSIONS + 420 + TYPE + 3 + UID + 0 + + + GID + 80 + PATH + Resources + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 2 + UID + 0 + + + GID + 80 + PATH + 360Daemon + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 2 + UID + 0 + + + GID + 80 + PATH + MICE + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 2 + UID + 0 + + + GID + 80 + PATH + Application Support + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + Documentation + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + Filesystems + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + Frameworks + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + Input Methods + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + Internet Plug-Ins + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + LaunchAgents + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + + CHILDREN + + GID + 0 + PATH + ../360Daemon/com.mice.360Daemon.plist + PATH_TYPE + 1 + PERMISSIONS + 420 + TYPE + 3 + UID + 0 + + + GID + 0 + PATH + LaunchDaemons + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + + CHILDREN + + GID + 0 + PATH + ../Pref360Control/build/Deployment/Pref360Control.prefPane + PATH_TYPE + 1 + PERMISSIONS + 493 + TYPE + 3 + UID + 0 + + + GID + 0 + PATH + PreferencePanes + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + Preferences + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 80 + PATH + Printers + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + PrivilegedHelperTools + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + QuickLook + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + QuickTime + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + Screen Savers + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + Scripts + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + Services + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + Widgets + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + GID + 0 + PATH + Library + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + + CHILDREN + + + CHILDREN + + + BUNDLE_CAN_DOWNGRADE + + CHILDREN + + GID + 0 + PATH + ../360Controller/build/Deployment/360Controller.kext + PATH_TYPE + 1 + PERMISSIONS + 493 + TYPE + 3 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + ../Wireless360Controller/build/Release/Wireless360Controller.kext + PATH_TYPE + 1 + PERMISSIONS + 493 + TYPE + 3 + UID + 0 + + + CHILDREN + + GID + 0 + PATH + ../WirelessGamingReceiver/build/Release/WirelessGamingReceiver.kext + PATH_TYPE + 1 + PERMISSIONS + 493 + TYPE + 3 + UID + 0 + + + GID + 0 + PATH + Extensions + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + GID + 0 + PATH + Library + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + GID + 0 + PATH + System + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + CHILDREN + + + CHILDREN + + GID + 0 + PATH + Shared + PATH_TYPE + 0 + PERMISSIONS + 1023 + TYPE + 1 + UID + 0 + + + GID + 80 + PATH + Users + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + + GID + 0 + PATH + / + PATH_TYPE + 0 + PERMISSIONS + 493 + TYPE + 1 + UID + 0 + + PAYLOAD_TYPE + 0 + VERSION + 2 + + PACKAGE_SCRIPTS + + POSTINSTALL_PATH + + PATH + Scripts/finish.sh + PATH_TYPE + 1 + + PREINSTALL_PATH + + PATH + Scripts/upgrade.sh + PATH_TYPE + 1 + + RESOURCES + + + PACKAGE_SETTINGS + + AUTHENTICATION + 1 + CONCLUSION_ACTION + 2 + IDENTIFIER + com.mice.pkg.Xbox360controller + NAME + Install360Controller + OVERWRITE_PERMISSIONS + + VERSION + 0.12 + + UUID + 95C3DB03-4C99-4A29-AEC7-C73B3D9F6A04 + + + PROJECT + + PROJECT_COMMENTS + + NOTES + + PCFET0NUWVBFIGh0bWwgUFVCTElDICItLy9XM0MvL0RURCBIVE1M + IDQuMDEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvVFIvaHRtbDQv + c3RyaWN0LmR0ZCI+CjxodG1sPgo8aGVhZD4KPG1ldGEgaHR0cC1l + cXVpdj0iQ29udGVudC1UeXBlIiBjb250ZW50PSJ0ZXh0L2h0bWw7 + IGNoYXJzZXQ9VVRGLTgiPgo8bWV0YSBodHRwLWVxdWl2PSJDb250 + ZW50LVN0eWxlLVR5cGUiIGNvbnRlbnQ9InRleHQvY3NzIj4KPHRp + dGxlPjwvdGl0bGU+CjxtZXRhIG5hbWU9IkdlbmVyYXRvciIgY29u + dGVudD0iQ29jb2EgSFRNTCBXcml0ZXIiPgo8bWV0YSBuYW1lPSJD + b2NvYVZlcnNpb24iIGNvbnRlbnQ9IjExODcuMzQiPgo8c3R5bGUg + dHlwZT0idGV4dC9jc3MiPgo8L3N0eWxlPgo8L2hlYWQ+Cjxib2R5 + Pgo8L2JvZHk+CjwvaHRtbD4K + + + PROJECT_PRESENTATION + + INSTALLATION TYPE + + HIERARCHIES + + INSTALLER + + LIST + + + DESCRIPTION + + OPTIONS + + HIDDEN + + STATE + 0 + + PACKAGE_UUID + 95C3DB03-4C99-4A29-AEC7-C73B3D9F6A04 + REQUIREMENTS + + TITLE + + TOOLTIP + + TYPE + 0 + UUID + CB32CFF6-F06D-4B81-B1A5-A040090A6BFB + + + REMOVED + + + + INSTALLATION TYPE + 0 + + INSTALLATION_STEPS + + + ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS + ICPresentationViewIntroductionController + INSTALLER_PLUGIN + Introduction + LIST_TITLE_KEY + InstallerSectionTitle + + + ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS + ICPresentationViewReadMeController + INSTALLER_PLUGIN + ReadMe + LIST_TITLE_KEY + InstallerSectionTitle + + + ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS + ICPresentationViewLicenseController + INSTALLER_PLUGIN + License + LIST_TITLE_KEY + InstallerSectionTitle + + + ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS + ICPresentationViewDestinationSelectController + INSTALLER_PLUGIN + TargetSelect + LIST_TITLE_KEY + InstallerSectionTitle + + + ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS + ICPresentationViewInstallationTypeController + INSTALLER_PLUGIN + PackageSelection + LIST_TITLE_KEY + InstallerSectionTitle + + + ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS + ICPresentationViewInstallationController + INSTALLER_PLUGIN + Install + LIST_TITLE_KEY + InstallerSectionTitle + + + ICPRESENTATION_CHAPTER_VIEW_CONTROLLER_CLASS + ICPresentationViewSummaryController + INSTALLER_PLUGIN + Summary + LIST_TITLE_KEY + InstallerSectionTitle + + + INTRODUCTION + + LOCALIZATIONS + + + LANGUAGE + English + VALUE + + PATH + Text/Welcome.rtf + PATH_TYPE + 1 + + + + + LICENSE + + KEYWORDS + + LOCALIZATIONS + + + LANGUAGE + English + VALUE + + PATH + ../Licence.txt + PATH_TYPE + 1 + + + + MODE + 0 + + README + + LOCALIZATIONS + + + LANGUAGE + English + VALUE + + PATH + ../Readme.rtf + PATH_TYPE + 1 + + + + + SUMMARY + + LOCALIZATIONS + + + TITLE + + LOCALIZATIONS + + + LANGUAGE + English + VALUE + Install360Controller + + + + + PROJECT_REQUIREMENTS + + LIST + + POSTINSTALL_PATH + + PREINSTALL_PATH + + RESOURCES + + ROOT_VOLUME_ONLY + + + PROJECT_SETTINGS + + ADVANCED_OPTIONS + + BUILD_FORMAT + 0 + BUILD_PATH + + PATH + build + PATH_TYPE + 1 + + CERTIFICATE + + NAME + Developer ID Installer: Colin Munro + PATH + /Users/colin/Library/Keychains/login.keychain + + EXCLUDED_FILES + + + PATTERNS_ARRAY + + + REGULAR_EXPRESSION + + STRING + .DS_Store + TYPE + 0 + + + PROTECTED + + PROXY_NAME + Remove .DS_Store files + PROXY_TOOLTIP + Remove ".DS_Store" files created by the Finder. + STATE + + + + PATTERNS_ARRAY + + + REGULAR_EXPRESSION + + STRING + .pbdevelopment + TYPE + 0 + + + PROTECTED + + PROXY_NAME + Remove .pbdevelopment files + PROXY_TOOLTIP + Remove ".pbdevelopment" files created by ProjectBuilder or Xcode. + STATE + + + + PATTERNS_ARRAY + + + REGULAR_EXPRESSION + + STRING + CVS + TYPE + 1 + + + REGULAR_EXPRESSION + + STRING + .cvsignore + TYPE + 0 + + + REGULAR_EXPRESSION + + STRING + .cvspass + TYPE + 0 + + + REGULAR_EXPRESSION + + STRING + .svn + TYPE + 1 + + + REGULAR_EXPRESSION + + STRING + .git + TYPE + 1 + + + REGULAR_EXPRESSION + + STRING + .gitignore + TYPE + 0 + + + PROTECTED + + PROXY_NAME + Remove SCM metadata + PROXY_TOOLTIP + Remove helper files and folders used by the CVS, SVN or Git Source Code Management systems. + STATE + + + + PATTERNS_ARRAY + + + REGULAR_EXPRESSION + + STRING + classes.nib + TYPE + 0 + + + REGULAR_EXPRESSION + + STRING + designable.db + TYPE + 0 + + + REGULAR_EXPRESSION + + STRING + info.nib + TYPE + 0 + + + PROTECTED + + PROXY_NAME + Optimize nib files + PROXY_TOOLTIP + Remove "classes.nib", "info.nib" and "designable.nib" files within .nib bundles. + STATE + + + + PATTERNS_ARRAY + + + REGULAR_EXPRESSION + + STRING + Resources Disabled + TYPE + 1 + + + PROTECTED + + PROXY_NAME + Remove Resources Disabled folders + PROXY_TOOLTIP + Remove "Resources Disabled" folders. + STATE + + + + SEPARATOR + + + + NAME + Install360Controller + + + TYPE + 0 + VERSION + 2 + + diff --git a/Install360Controller/Scripts/finish.sh b/Install360Controller/Scripts/finish.sh new file mode 100644 index 00000000..6f058a87 --- /dev/null +++ b/Install360Controller/Scripts/finish.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +/usr/bin/touch /System/Library/Extensions + +exit 0 diff --git a/Install360Controller/Scripts/upgrade.sh b/Install360Controller/Scripts/upgrade.sh new file mode 100644 index 00000000..c0283260 --- /dev/null +++ b/Install360Controller/Scripts/upgrade.sh @@ -0,0 +1,38 @@ +#!/bin/sh + +# Clear out daemon + +if [ -d /Library/StartupItems/360ControlDaemon ]; then + /bin/rm -r /Library/StartupItems/360ControlDaemon +fi + +if [ -f /Library/LaunchDaemons/com.mice.360Daemon.plist ]; then + launchctl stop com.mice.360Daemon + /bin/rm /Library/LaunchDaemons/com.mice.360Daemon.plist +fi + +if [ -d /Library/Application\ Support/MICE/360Daemon ]; then + /bin/rm -r /Library/Application\ Support/MICE/360Daemon +fi + +# Remove preference pane + +if [ -d /Library/PreferencePanes/Pref360Control.prefPane ]; then + /bin/rm -r /Library/PreferencePanes/Pref360Control.prefPane +fi + +# Remove drivers + +if [ -d /System/Library/Extensions/360Controller.kext ]; then + /bin/rm -r /System/Library/Extensions/360Controller.kext +fi + +if [ -d /System/Library/Extensions/Wireless360Controller.kext ]; then + /bin/rm -r /System/Library/Extensions/Wireless360Controller.kext +fi + +if [ -d /System/Library/Extensions/WirelessGamingReceiver.kext ]; then + /bin/rm -r /System/Library/Extensions/WirelessGamingReceiver.kext +fi + +exit 0 diff --git a/Install360Controller/Text/Welcome.rtf b/Install360Controller/Text/Welcome.rtf new file mode 100644 index 00000000..5ebcf3d6 --- /dev/null +++ b/Install360Controller/Text/Welcome.rtf @@ -0,0 +1,148 @@ +{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +{\*\listtable{\list\listtemplateid1\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid1\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid1} +{\list\listtemplateid2\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid101\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid2} +{\list\listtemplateid3\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid201\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid3} +{\list\listtemplateid4\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid301\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid4} +{\list\listtemplateid5\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid401\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid5} +{\list\listtemplateid6\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid501\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid6} +{\list\listtemplateid7\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid601\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid7} +{\list\listtemplateid8\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid701\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid8} +{\list\listtemplateid9\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid801\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid9} +{\list\listtemplateid10\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid901\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid10} +{\list\listtemplateid11\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid1001\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid11}} +{\*\listoverridetable{\listoverride\listid1\listoverridecount0\ls1}{\listoverride\listid2\listoverridecount0\ls2}{\listoverride\listid3\listoverridecount0\ls3}{\listoverride\listid4\listoverridecount0\ls4}{\listoverride\listid5\listoverridecount0\ls5}{\listoverride\listid6\listoverridecount0\ls6}{\listoverride\listid7\listoverridecount0\ls7}{\listoverride\listid8\listoverridecount0\ls8}{\listoverride\listid9\listoverridecount0\ls9}{\listoverride\listid10\listoverridecount0\ls10}{\listoverride\listid11\listoverridecount0\ls11}} +\paperw12240\paperh15840\margl1440\margr1440\vieww14760\viewh12840\viewkind0 +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural + +\f0\b\fs42 \cf0 XBox 360 Controller Driver\ + +\b0\fs24 Version 0.12\ +Copyright (C) 2005-2013 Colin Munro\ +\ +Welcome to the installer for the XBox 360 Controller driver for Mac OS X.\ +\ + +\b Update 0.12: 4/01/2013\ + +\b0 \ +This update includes:\ +\pard\tx220\tx720\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li720\fi-720\pardirnatural +\ls1\ilvl0\cf0 {\listtext \'95 }Fix that prevents non-ChatPad-compatible controllers from working\ +{\listtext \'95 }Improvement to ChatPad support\ +{\listtext \'95 }Improvement to wireless support (automatic and manual power-off)\ +{\listtext \'95 }Updated Info.plist with many common devices\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural +\cf0 \ + +\b Update 0.11: 10/01/2012\ + +\b0 \ +This update includes:\ +\pard\tx220\tx720\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li720\fi-720\pardirnatural +\ls2\ilvl0\cf0 {\listtext \'95 }Temporary Lion fix (thanks to "codeman38")\ +{\listtext \'95 }Adjustment to the automatic device match function\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural +\cf0 \ + +\b Update 0.10: 8/05/2011\ + +\b0 \ +This update includes:\ +\pard\tx220\tx720\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li720\fi-720\pardirnatural +\ls3\ilvl0\cf0 {\listtext \'95 }Various bugfixes\ +{\listtext \'95 }New product IDs for Wireless Gaming Receiver\ +{\listtext \'95 }Automatic device match function, allowing you to select and deselect which controllers you want it to match with\ +{\listtext \'95 }Fix the incompatibility with Bioshock introduced with ChatPad support\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural +\cf0 \ + +\b Update 0.09: 21/11/2009\ + +\b0 \ +This update includes:\ +\pard\tx220\tx720\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li720\fi-720\pardirnatural +\ls4\ilvl0\cf0 {\listtext \'95 }Driver rearchitecture\ +{\listtext \'95 }ChatPad support in wired controller\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural + +\b \cf0 \ +Update 0.08: 10/09/2009\ + +\b0 \ +This update includes:\ +\pard\tx220\tx720\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li720\fi-720\pardirnatural +\ls5\ilvl0\cf0 {\listtext \'95 }64-bit support (untested)\ +{\listtext \'95 }Fix for Snow Leopard\ +{\listtext \'95 }Minor bugfixes\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural +\cf0 \ + +\b Update 0.07: 16/12/2007\ + +\b0 \ +This update includes:\ +\pard\tx220\tx720\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li720\fi-720\pardirnatural +\ls6\ilvl0\cf0 {\listtext \'95 }10.4 bugfix\ +{\listtext \'95 }Extra controller IDs\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural +\cf0 \ + +\b Update 0.06: 10/11/2007 +\b0 \ +\ +This update includes:\ +\pard\tx220\tx720\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li720\fi-720\pardirnatural +\ls7\ilvl0\cf0 {\listtext \'95 }Improvements to the wireless support\ +{\listtext \'95 }Daemon providing persistent settings and LED setting\ +{\listtext \'95 }Bugfix to support Halo\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural +\cf0 \ + +\b Update 0.05: 21/4/2007 +\b0 \ +\ +This update includes:\ +\pard\tx220\tx720\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li720\fi-720\pardirnatural +\ls8\ilvl0\cf0 {\listtext \'95 }Improvements to the wireless support\ +{\listtext \'95 }New increased compatibility with games\ +{\listtext \'95 }Support for the Guitar Hero controller\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural +\cf0 \ + +\b Update 0.04: 27/2/2007\ + +\b0 \ +This update includes:\ +\pard\tx220\tx720\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li720\fi-720\pardirnatural +\ls9\ilvl0\cf0 {\listtext \'95 }Driver for the Microsoft Wireless Gaming Receiver for Windows\ +{\listtext \'95 }Driver for the above to use the Wireless 360 Controller\ +{\listtext \'95 }Updates to the Preference Pane to support the Wireless 360 Controller\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural +\cf0 \ + +\b Update 0.03: 22/7/2006\ + +\b0 \ +This update includes:\ +\pard\tx220\tx720\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li720\fi-720\pardirnatural +\ls10\ilvl0\cf0 {\listtext \'95 }More 3rd party vendor/product IDs\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural +\cf0 \ + +\b Update 0.02: 11/2/2006 +\b0 \ +\ +This update includes:\ +\pard\tx220\tx720\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li720\fi-720\pardirnatural +\ls11\ilvl0\cf0 {\listtext \'95 }Universal binaries, for Intel Mac support\ +{\listtext \'95 }Additional 3rd party vendor/product IDs (support for matching on interface instead of IDs still isn't working)\ +{\listtext \'95 }Preference Pane now correctly detects devices being connected/disconnected\ +{\listtext \'95 }Alternative deadzone mode\ +{\listtext \'95 }D-pad moved from pointer to plain joypad buttons, for better support in games\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural +\cf0 \ +Please visit {\field{\*\fldinst{HYPERLINK "http://tattiebogle.net/index.php/ProjectRoot/Xbox360Controller/OsxDriver"}}{\fldrslt http://tattiebogle.net/index.php/ProjectRoot/Xbox360Controller/OsxDriver}} for information on this software. Consider donating or buying via the Amazon associate links to support development of this driver!\ +\ +Ensure to read the following Read Me and License sections before installing!} \ No newline at end of file diff --git a/Licence.txt b/Licence.txt new file mode 100644 index 00000000..3912109b --- /dev/null +++ b/Licence.txt @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Pref360Control/DeviceItem.h b/Pref360Control/DeviceItem.h new file mode 100644 index 00000000..4c27482f --- /dev/null +++ b/Pref360Control/DeviceItem.h @@ -0,0 +1,44 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + DeviceItem.h - declaration of wrapper class for device handles + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#import +#import +#import +#import +#import +#import + +@interface DeviceItem : NSObject { + IOHIDDeviceInterface122 **interface; + FFDeviceObjectReference forceFeedback; + io_service_t deviceHandle; + NSString *deviceName; +} + ++ allocateDeviceItemForDevice:(io_service_t)device; + +- (NSString*)name; +- (IOHIDDeviceInterface122**)hidDevice; +- (FFDeviceObjectReference)ffDevice; +- (io_service_t)rawDevice; + +@end diff --git a/Pref360Control/DeviceItem.m b/Pref360Control/DeviceItem.m new file mode 100644 index 00000000..2fba7cf9 --- /dev/null +++ b/Pref360Control/DeviceItem.m @@ -0,0 +1,100 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + DeviceItem.m - implementation of device wrapper class + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#import "DeviceItem.h" + +static NSString* GetDeviceName(io_service_t device) +{ + CFMutableDictionaryRef serviceProperties; + NSDictionary *properties; + NSString *deviceName = nil; + + if (IORegistryEntryCreateCFProperties(device, &serviceProperties, kCFAllocatorDefault, kNilOptions) != KERN_SUCCESS) + return nil; + properties = (NSDictionary*)serviceProperties; + deviceName = [properties objectForKey:(NSString*)CFSTR(kIOHIDProductKey)]; + if (deviceName == nil) + deviceName = [properties objectForKey:@"USB Product Name"]; + [deviceName retain]; + CFRelease(serviceProperties); + return deviceName; +} + +@implementation DeviceItem + ++ allocateDeviceItemForDevice:(io_service_t)device +{ + DeviceItem *item; + IOReturn ret; + IOCFPlugInInterface **plugInInterface; + SInt32 score=0; + + item=[[[DeviceItem alloc] init] autorelease]; + if(item==nil) goto fail; + ret=IOCreatePlugInInterfaceForService(device,kIOHIDDeviceUserClientTypeID,kIOCFPlugInInterfaceID,&plugInInterface,&score); + if(ret!=kIOReturnSuccess) goto fail; + ret=(*plugInInterface)->QueryInterface(plugInInterface,CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID122),(LPVOID)&item->interface); + (*plugInInterface)->Release(plugInInterface); + if(ret!=kIOReturnSuccess) goto fail; + item->forceFeedback=0; + FFCreateDevice(device,&item->forceFeedback); + item->deviceHandle=device; + item->deviceName = GetDeviceName(device); + return item; +fail: + IOObjectRelease(device); + return NULL; +} + +- (void)dealloc +{ + if(deviceHandle != 0) + IOObjectRelease(deviceHandle); + if(interface != NULL) + (*interface)->Release(interface); + if(forceFeedback != 0) + FFReleaseDevice(forceFeedback); + [deviceName release]; + [super dealloc]; +} + +- (NSString*)name +{ + return deviceName; +} + +- (IOHIDDeviceInterface122**)hidDevice +{ + return interface; +} + +- (FFDeviceObjectReference)ffDevice +{ + return forceFeedback; +} + +- (io_service_t)rawDevice +{ + return deviceHandle; +} + +@end diff --git a/Pref360Control/DeviceLister.h b/Pref360Control/DeviceLister.h new file mode 100644 index 00000000..041f802a --- /dev/null +++ b/Pref360Control/DeviceLister.h @@ -0,0 +1,41 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + DeviceLister.h - decleration of a class to display supported devices + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#import + +@class Pref360ControlPref; + +@interface DeviceLister : NSObject { + Pref360ControlPref *owner; + IBOutlet NSWindow *sheet; + IBOutlet NSTableView *list; + + NSMutableDictionary *entries; + NSMutableArray *connected, *enabled; + + BOOL changed; +} + +- (void)showWithOwner:(Pref360ControlPref*)pane; +- (IBAction)done:(id)sender; + +@end diff --git a/Pref360Control/DeviceLister.m b/Pref360Control/DeviceLister.m new file mode 100644 index 00000000..027d4db7 --- /dev/null +++ b/Pref360Control/DeviceLister.m @@ -0,0 +1,522 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + DeviceLister.m - implementation of a class to list supported devices + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ +#import +#import "DeviceLister.h" +#import "Pref360ControlPref.h" +#import "ControlPrefs.h" + +#define TOOL_FILENAME @"DriverTool" + +// Get some sort of CF type for a field in the IORegistry +static id GetDeviceValue(io_service_t device, NSString *key) +{ + CFTypeRef value; + + value = IORegistryEntrySearchCFProperty(device, kIOServicePlane, (CFStringRef)key, kCFAllocatorDefault, kIORegistryIterateRecursively); + return [((NSObject*)value) autorelease]; +} + +// Make sure a name is as nice as possible for eventually going into the XML for the driver +static NSString* SanitiseName(NSString *name) +{ + NSMutableString *output; + int i; + + output = [NSMutableString stringWithCapacity:100]; + for (i = 0; i < [name length]; i++) + { + unichar c = [name characterAtIndex:i]; + if (c == ' ') + c = '_'; + else if (!(((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')) || ((c >= '0') && (c <= '9')) || (c == '_'))) + continue; + [output appendFormat:@"%C", c]; + } + return output; +} + +// Get the Device interface for a given IO service +static IOUSBDeviceInterface** GetDeviceInterface(io_service_t device) +{ + IOCFPlugInInterface **iodev; + IOUSBDeviceInterface **dev; + IOReturn err; + SInt32 score; + + if ((IOCreatePlugInInterfaceForService(device, kIOUSBDeviceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score) == kIOReturnSuccess) && (iodev != NULL)) + { + err = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBDeviceInterfaceID), (LPVOID)&dev); + (*iodev)->Release(iodev); + if (err == kIOReturnSuccess) + return dev; + } + return NULL; +} + +// Get the Interface interface for a given IO service +static IOUSBInterfaceInterface** GetInterfaceInterface(io_service_t interface) +{ + IOCFPlugInInterface **iodev; + IOUSBInterfaceInterface **intf; + IOReturn err; + SInt32 score; + + if ((IOCreatePlugInInterfaceForService(interface, kIOUSBInterfaceUserClientTypeID, kIOCFPlugInInterfaceID, &iodev, &score) == kIOReturnSuccess) && (iodev != NULL)) + { + err = (*iodev)->QueryInterface(iodev, CFUUIDGetUUIDBytes(kIOUSBInterfaceInterfaceID), (LPVOID)&intf); + (*iodev)->Release(iodev); + if (err == kIOReturnSuccess) + return intf; + } + return NULL; +} + +// List of interfaces we expect on a normal Microsoft controller +const struct { + int numEndpoints; + UInt8 classNum, subClassNum, protocolNum; +} ControllerInterfaces[] = { +// Endpoints Class Subclass Protocol + {2, 255, 93, 1}, + {4, 255, 93, 3}, + {1, 255, 93, 2}, + {0, 255, 253, 19}, +}; + +// Detect if an IO service object is a Microsoft controller by running through and checking some things +static BOOL IsXBox360Controller(io_service_t device) +{ + IOUSBDeviceInterface **interface; + IOUSBFindInterfaceRequest iRq; + io_iterator_t iterator; + io_service_t devInterface; + IOUSBInterfaceInterface **interfaceInterface; + + int interfaceCount; + UInt8 interfaceNum, classNum, subClassNum, protocolNum, endpointCount; + + BOOL devValid; + + // Get the interface to the device + interface = GetDeviceInterface(device); + if (interface == NULL) + return NO; + (*interface)->GetDeviceClass(interface, &classNum); + (*interface)->GetDeviceSubClass(interface, &subClassNum); + (*interface)->GetDeviceProtocol(interface, &protocolNum); + devValid = (classNum == 0xFF) && (subClassNum == 0xFF) && (protocolNum == 0xFF); + + // Search the interfaces + iRq.bInterfaceClass = kIOUSBFindInterfaceDontCare; + iRq.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; + iRq.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; + iRq.bAlternateSetting = kIOUSBFindInterfaceDontCare; + interfaceCount = 0; + if ((*interface)->CreateInterfaceIterator(interface, &iRq, &iterator) == kIOReturnSuccess) + { + while ((devInterface = IOIteratorNext(iterator)) != 0) + { + interfaceInterface = GetInterfaceInterface(devInterface); + if (interfaceInterface != NULL) + { + (*interfaceInterface)->GetInterfaceNumber(interfaceInterface, &interfaceNum); + (*interfaceInterface)->GetInterfaceClass(interfaceInterface, &classNum); + (*interfaceInterface)->GetInterfaceSubClass(interfaceInterface, &subClassNum); + (*interfaceInterface)->GetInterfaceProtocol(interfaceInterface, &protocolNum); + (*interfaceInterface)->GetNumEndpoints(interfaceInterface, &endpointCount); + if (interfaceNum < (sizeof(ControllerInterfaces) / sizeof(ControllerInterfaces[0]))) + { + if ( + (ControllerInterfaces[interfaceNum].classNum == classNum) + && + (ControllerInterfaces[interfaceNum].subClassNum == subClassNum) + && + (ControllerInterfaces[interfaceNum].protocolNum == protocolNum) + && + (ControllerInterfaces[interfaceNum].numEndpoints == endpointCount) + ) + { + // Found another interface in the right place + interfaceCount++; + } + } + (*interfaceInterface)->Release(interfaceInterface); + } + IOObjectRelease(devInterface); + } + IOObjectRelease(iterator); + } + + // Done + (*interface)->Release(interface); + + return devValid && (interfaceCount >= 3); // Only 3 in case the security descriptor is missing? +} + +@implementation DeviceLister + +- init +{ + if (self = [super init]) + { + entries = [[NSMutableDictionary dictionaryWithCapacity:10] retain]; + connected = [[NSMutableArray arrayWithCapacity:10] retain]; + enabled = [[NSMutableArray arrayWithCapacity:10] retain]; + } + return self; +} + +- (void)dealloc +{ + [entries release]; + [connected release]; + [enabled release]; + [super dealloc]; +} + +- (NSString*)toolPath +{ + // Find the path of our tool in our bundle - should it be in the driver's bundle? + return [[[owner bundle] resourcePath] stringByAppendingPathComponent:TOOL_FILENAME]; +} + +- (OSStatus)writeToolWithAuthorisation:(AuthorizationRef)authorisationRef +{ + OSStatus result; + NSString *toolPath; + NSMutableArray *parameters; + const char **argv; + int i; + + toolPath = [self toolPath]; + + // Build array of parameters + parameters = [NSMutableArray arrayWithCapacity:10]; + [parameters addObject:@"edit"]; + + for (NSNumber *key in enabled) + { + NSString *name = [entries objectForKey:key]; + NSUInteger keyValue = [key unsignedIntValue]; + UInt16 vendor = (keyValue >> 16) & 0xFFFF; + UInt16 product = keyValue & 0xFFFF; + [parameters addObject:name]; + [parameters addObject:[NSString stringWithFormat:@"%i", vendor]]; + [parameters addObject:[NSString stringWithFormat:@"%i", product]]; + } + + // Convert parameters to a C array + argv = malloc(sizeof(char*) * ([parameters count] + 1)); + i = 0; + for (NSString *item in parameters) + argv[i++] = [item UTF8String]; + argv[i] = NULL; + + // Execute the command + result = AuthorizationExecuteWithPrivileges(authorisationRef, + [toolPath UTF8String], + kAuthorizationFlagDefaults, + (char**)argv, + NULL); + + // Done + free(argv); + return result; +} + +- (NSString*)readTool +{ + NSTask *task; + NSPipe *pipe, *error; + NSData *data; + NSString *response; + NSArray *lines; + + // Prepare to run the tool + task = [[[NSTask alloc] init] autorelease]; + [task setLaunchPath:[self toolPath]]; + + // Hook up the pipe to catch the output + pipe = [NSPipe pipe]; + [task setStandardOutput:pipe]; + error = [NSPipe pipe]; + [task setStandardError:error]; + + // Run the tool + [task launch]; + [task waitUntilExit]; + + // Check result + if ([task terminationStatus] != 0) + { + data = [[error fileHandleForReading] readDataToEndOfFile]; + return [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; + } + + // Read the data back + data = [[pipe fileHandleForReading] readDataToEndOfFile]; + response = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; + + // Parse the results + lines = [response componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]; + for (NSString *line in lines) + { + NSArray *values = [line componentsSeparatedByString:@","]; + if ([values count] != 3) + continue; + NSUInteger vendor = [[values objectAtIndex:1] intValue]; + NSUInteger product = [[values objectAtIndex:2] intValue]; + NSNumber *key = [NSNumber numberWithUnsignedInt:(int)((vendor << 16) | product)]; + [enabled addObject:key]; + if ([entries objectForKey:key] == nil) + [entries setObject:SanitiseName([values objectAtIndex:0]) forKey:key]; + } + + return nil; +} + +// Get the list of devices we've seen from the settings +- (NSString*)readKnownDevices +{ + NSDictionary *known; + NSArray *keys; + + known = GetKnownDevices(); + keys = [known allKeys]; + for (NSNumber *key in keys) + { + if ([entries objectForKey:key] == nil) + [entries setObject:[known objectForKey:key] forKey:key]; + } + return nil; +} + +// Find any matching devices currently plugged in +- (NSString*)readIOKit +{ + io_iterator_t iterator; + io_service_t object; + + iterator = 0; + IOServiceGetMatchingServices([owner masterPort], IOServiceMatching(kIOUSBDeviceClassName), &iterator); + if (iterator != 0) + { + while ((object = IOIteratorNext(iterator)) != 0) + { + if (IsXBox360Controller(object)) + { + NSNumber *vendorValue, *productValue; + UInt16 vendor,product; + + vendorValue = GetDeviceValue(object, @"idVendor"); + vendor = [vendorValue intValue]; + + productValue = GetDeviceValue(object, @"idProduct"); + product = [productValue intValue]; + + if ((vendorValue != nil) && (productValue != nil)) + { + NSNumber *key; + + key = [NSNumber numberWithUnsignedInt:(vendor << 16) | product]; + [connected addObject:key]; + if ([entries objectForKey:key] == nil) + { + NSString *name = GetDeviceValue(object, @"USB Product Name"); + if (name == nil) + name = [NSString stringWithFormat:@"Unknown_%.4x_%.4x", vendor, product]; + else + name = SanitiseName(name); + [entries setObject:name forKey:key]; + } + } + } + IOObjectRelease(object); + } + IOObjectRelease(iterator); + } + return nil; +} + +- (void)showFailure:(NSString*)message +{ + NSAlert *alert = [NSAlert alertWithMessageText:nil + defaultButton:nil + alternateButton:nil + otherButton:nil + informativeTextWithFormat:@"%@", message]; + [alert runModal]; +} + +- (BOOL)loadDevices +{ + NSString *error; + + // Initialise + error = nil; + [entries removeAllObjects]; + [connected removeAllObjects]; + [enabled removeAllObjects]; + + // These can be done in any order, depending on the behaviour desired + if (error == nil) + error = [self readKnownDevices]; + if (error == nil) + error = [self readTool]; + if (error == nil) + error = [self readIOKit]; + + // Check for errors + if (error != nil) + { + [self showFailure:error]; + return NO; + } + + // Done + SetKnownDevices(entries); + [list reloadData]; + changed = NO; + return YES; +} + +// attempt to authenticate so we can edit the driver's list of supported devices as root +- (BOOL)trySave +{ + OSStatus status; + AuthorizationRef authorisationRef; + BOOL success = NO; + + status = AuthorizationCreate(NULL, + kAuthorizationEmptyEnvironment, + kAuthorizationFlagDefaults, + &authorisationRef); + if (status != errAuthorizationSuccess) + { + [self showFailure:NSLocalizedString(@"Unable to create authorisation request", @"")]; + return NO; + } + + AuthorizationItem right = {kAuthorizationRightExecute, 0, NULL, 0}; + AuthorizationRights rights = {1, &right}; + status = AuthorizationCopyRights(authorisationRef, + &rights, + NULL, + kAuthorizationFlagDefaults | kAuthorizationFlagInteractionAllowed | kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights, + NULL); + if (status != errAuthorizationSuccess) + { + [self showFailure:NSLocalizedString(@"Unable to acquire authorisation", @"")]; + goto fail; + } + + status = [self writeToolWithAuthorisation:authorisationRef]; + if (status != errAuthorizationSuccess) + { + [self showFailure:NSLocalizedString(@"Failed to execute the driver tool", @"")]; + goto fail; + } + + success = YES; + +fail: + AuthorizationFree(authorisationRef, kAuthorizationFlagDestroyRights); + return success; +} + +- (void)showWithOwner:(Pref360ControlPref*)pane +{ + owner = pane; + if (![self loadDevices]) + return; + [NSApp beginSheet:sheet + modalForWindow:[NSApp mainWindow] + modalDelegate:nil + didEndSelector:nil + contextInfo:NULL]; +} + +- (IBAction)done:(id)sender +{ + if (changed) + [self trySave]; + [NSApp endSheet:sheet]; + [sheet close]; +} + +// NSTableView data source + +- (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView +{ + return [entries count]; +} + +- (id)tableView:(NSTableView*)aTableView objectValueForTableColumn:(NSTableColumn*)aTableColumn row:(NSInteger)rowIndex +{ + NSString *identifier = [aTableColumn identifier]; + NSString *key = [[entries allKeys] objectAtIndex:rowIndex]; + if ([identifier compare:@"enable"] == NSOrderedSame) + { + return [NSNumber numberWithBool:[enabled containsObject:key]]; + } + if ([identifier compare:@"name"] == NSOrderedSame) + { + NSColor *colour; + + if ([connected containsObject:key]) + colour = [NSColor blueColor]; + else + colour = [NSColor blackColor]; + return [[[NSAttributedString alloc] initWithString:[entries objectForKey:key] + attributes:[NSDictionary dictionaryWithObject:colour forKey:NSForegroundColorAttributeName]] autorelease]; + } + return nil; +} + +- (void)tableView:(NSTableView*)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn*)aTableColumn row:(NSInteger)rowIndex +{ + if ([(NSString*)[aTableColumn identifier] compare:@"enable"] == NSOrderedSame) + { + NSString *key = [[entries allKeys] objectAtIndex:rowIndex]; + BOOL contains = [enabled containsObject:key]; + if ([(NSNumber*)anObject boolValue]) + { + if (!contains) + { + [enabled addObject:key]; + changed = YES; + } + } + else + { + if (contains) + { + [enabled removeObject:key]; + changed = YES; + } + } + + } +} + +@end diff --git a/Pref360Control/English.lproj/InfoPlist.strings b/Pref360Control/English.lproj/InfoPlist.strings new file mode 100644 index 00000000..6542423e Binary files /dev/null and b/Pref360Control/English.lproj/InfoPlist.strings differ diff --git a/Pref360Control/English.lproj/Pref360ControlPref.nib/designable.nib b/Pref360Control/English.lproj/Pref360ControlPref.nib/designable.nib new file mode 100644 index 00000000..16ccac1d --- /dev/null +++ b/Pref360Control/English.lproj/Pref360ControlPref.nib/designable.nib @@ -0,0 +1,2148 @@ + + + + 1050 + 12C60 + 2844 + 1187.34 + 625.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 2844 + + + NSBox + NSButton + NSButtonCell + NSCustomObject + NSCustomView + NSImageCell + NSImageView + NSMenu + NSMenuItem + NSPopUpButton + NSPopUpButtonCell + NSProgressIndicator + NSScrollView + NSScroller + NSSlider + NSSliderCell + NSTableColumn + NSTableView + NSTextField + NSTextFieldCell + NSView + NSWindowTemplate + + + com.apple.InterfaceBuilder.CocoaPlugin + + + PluginDependencyRecalculationVersion + + + + + Pref360ControlPref + + + FirstResponder + + + NSApplication + + + 7 + 2 + {{240, 597}, {595, 304}} + 1081606144 + << do not localize >> + NSWindow + + View + + + {595, 10} + + + 256 + + + + 256 + {{107, 260}, {471, 26}} + + + + YES + + -2076180416 + 2048 + + LucidaGrande + 13 + 1044 + + + 109199360 + 1 + + LucidaGrande + 13 + 16 + + + + + + 400 + 75 + + + Item1 + + 1048576 + 2147483647 + 1 + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + _popUpItemAction: + + + YES + + + OtherViews + + + + + + Item2 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + Item3 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + 3 + YES + YES + 1 + + NO + + + + 256 + {{40, 266}, {65, 17}} + + + + YES + + 67108864 + 71303168 + RGV2aWNlOgo + + + + 6 + System + controlColor + + 3 + MC42NjY2NjY2NjY3AA + + + + 6 + System + controlTextColor + + 3 + MAA + + + + NO + + + + 256 + {{43, 117}, {77, 77}} + + + + MyAnalogStick + NSView + + + + 256 + {{123, 43}, {77, 77}} + + + + MyDigitalStick + NSView + + + + 256 + {{226, 43}, {77, 77}} + + + + MyAnalogStick + NSView + + + + 256 + {{306, 117}, {77, 77}} + + + + MyMainButtons + NSView + + + + 256 + {{151, 141}, {126, 39}} + + + + MyCentreButtons + NSView + + + + 256 + {{43, 202}, {77, 18}} + + + + MyShoulderButton + NSView + + + + 256 + {{306, 202}, {77, 18}} + + + + MyShoulderButton + NSView + + + + 1280 + {{41, 224}, {161, 20}} + + + + 16392 + 255 + + + + 1280 + {{224, 224}, {161, 20}} + + + + 16392 + 255 + + + + 256 + {{41, 93}, {71, 18}} + + + + YES + + 67108864 + 0 + Invert X + + + 1211912448 + 2 + + NSSwitch + + + + 200 + 25 + + NO + + + + 256 + {{41, 73}, {71, 18}} + + + + YES + + 67108864 + 0 + Invert Y + + + 1211912448 + 2 + + + + 200 + 25 + + NO + + + + 256 + {{309, 81}, {71, 18}} + + + + YES + + 67108864 + 0 + Invert X + + + 1211912448 + 2 + + + + 200 + 25 + + NO + + + + 256 + {{309, 61}, {71, 18}} + + + + YES + + 67108864 + 0 + Invert Y + + + 1211912448 + 2 + + + + 200 + 25 + + NO + + + + 256 + {{224, 16}, {161, 21}} + + + + YES + + 67108864 + 0 + + + + + Helvetica + 12 + 16 + + + 32768 + 0.0 + 50 + 0.0 + 0 + 1 + NO + NO + + NO + + + + 256 + {{41, 53}, {64, 18}} + + + + YES + + 67108864 + 0 + Linked + + + 1211912448 + 2 + + + + 200 + 25 + + NO + + + + 256 + {{309, 41}, {64, 18}} + + + + YES + + 67108864 + 0 + Linked + + + 1211912448 + 2 + + + + 200 + 25 + + NO + + + + 256 + + + + 274 + + + + 256 + {{13, 193}, {153, 14}} + + + + YES + + 67108864 + 272629760 + Xbox 360 Controller Driver + + LucidaGrande + 11 + 3100 + + + + + + NO + + + + 256 + {{13, 173}, {129, 17}} + + + + YES + + 67108864 + 272629760 + Version 0.12 + + LucidaGrande + 10 + 2843 + + + + + + NO + + + + 256 + {{13, 157}, {129, 17}} + + + + YES + + 67108864 + 272629760 + (C) 2006-13 Colin Munro + + + + + + NO + + + + 256 + {{10, 138}, {129, 14}} + + + + YES + + 69206017 + 272629760 + http://tattiebogle.net/ + + + + + + NO + + + + 256 + {{10, 116}, {153, 14}} + + + + YES + + 69206017 + 272629760 + http://mice-software.com/ + + + + + + NO + + + + 256 + {{13, 11}, {150, 97}} + + + YES + + 67108864 + 272629760 + Rm9yIG1vcmUgaW5mb3JtYXRpb24gb24gdGhpcyBkcml2ZXIsIHBsZWFzZSBzZWUgdGhlIHN1cHBsaWVk +IFJlYWRtZSBhbmQgTGljZW5jZSBkb2N1bWVudHMuCgpQbGVhc2UgY29uc2lkZXIgZG9uYXRpbmcgaWYg +eW91IGVuam95IHRoaXMgZHJpdmVyIQ + + + + + + NO + + + {{2, 2}, {179, 218}} + + + + + + {{395, 16}, {183, 235}} + + + + {0, 0} + + 67108864 + 0 + About + + + 6 + System + textBackgroundColor + + 3 + MQA + + + + 3 + MCAwLjgwMDAwMDAxMTkAA + + + + 3 + 0 + 2 + NO + + + + 256 + + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type + + {{197, 190}, {32, 24}} + + + + YES + + 134217728 + 33554432 + + NSImage + battNone + + 0 + 1 + 0 + YES + + NO + YES + + + + 268 + {{17, 40}, {21, 156}} + + + + YES + + 67108864 + 0 + + + 32768 + 0.0 + 50 + 0.0 + 0 + 0 + NO + YES + + NO + + + + -2147483380 + {{8, 254}, {39, 38}} + + + + YES + + 67108864 + 134217728 + + + + LucidaGrande + 18 + 16 + + + -2034499584 + 7 + + + 200 + 25 + + NO + + + + -2147483380 + {{62, 9}, {118, 32}} + + + + YES + + 67108864 + 134217728 + Power off + + + -2038284288 + 129 + + + 200 + 25 + + NO + + + {595, 304} + + + + + {{0, 0}, {1280, 1002}} + {595, 32} + {10000000000000, 10000000000000} + YES + + + 15 + 2 + {{131, 166}, {519, 336}} + 1685585920 + Window + NSWindow + + + {490, 150} + + + 256 + + + + 274 + + + + 2304 + + + + 256 + {477, 229} + + YES + NO + YES + + + -2147483392 + {{224, 0}, {16, 17}} + + + + enable + 20 + 20 + 20 + + 75497536 + 2048 + + + + 3 + MC4zMzMzMzI5ODU2AA + + + 6 + System + headerTextColor + + + + + 67108864 + 131072 + + + + 1211912448 + 2 + + NSImage + NSSwitch + + + + + 200 + 25 + + 1 + YES + YES + + + + name + 451 + 40 + 1000 + + 75497536 + 2048 + + + + + + + 337641536 + 2048 + Text Cell + + + + 6 + System + controlBackgroundColor + + + + + 1 + YES + + + + 3 + 2 + + + 6 + System + gridColor + + 3 + MC41AA + + + 17 + -700448768 + + + 4 + 15 + 0 + YES + 0 + 1 + + + {{1, 1}, {477, 229}} + + + + + 4 + + + + -2147483392 + {{224, 17}, {15, 102}} + + NO + + _doScroller: + 0.9925373134328358 + + + + -2147483392 + {{-100, -100}, {223, 15}} + + NO + 1 + + _doScroller: + 0.57142859697341919 + + + {{20, 60}, {479, 231}} + + + 133650 + + + + QSAAAEEgAABBmAAAQZgAAA + 0.25 + 4 + 1 + + + + 268 + {{17, 299}, {355, 17}} + + YES + + 68157504 + 272630784 + Select the devices you would like to use with the driver: + + + + + + NO + + + + 289 + {{409, 12}, {96, 32}} + + YES + + 67108864 + 134217728 + Done + + + -2038284288 + 129 + + + 200 + 25 + + NO + + + + 292 + {{17, 16}, {323, 28}} + + YES + + 68157504 + 272630784 + To save changes to this list, you must enter your password.
A restart will be required for changes to take effect. + + LucidaGrande + 11 + 16 + + + + + + NO + + + {519, 336} + + {{0, 0}, {1280, 1002}} + {490, 172} + {10000000000000, 10000000000000} + YES + + + DeviceLister + + + + + + + _window + + + + 26 + + + + leftStickInvertY + + + + 127 + + + + rightStickInvertX + + + + 128 + + + + rightStickInvertY + + + + 129 + + + + deviceList + + + + 130 + + + + rightStickDeadzone + + + + 134 + + + + rightStick + + + + 136 + + + + leftTrigger + + + + 137 + + + + rightTrigger + + + + 138 + + + + leftShoulder + + + + 139 + + + + rightShoulder + + + + 140 + + + + digiStick + + + + 141 + + + + centreButtons + + + + 142 + + + + rightButtons + + + + 143 + + + + leftStick + + + + 144 + + + + leftStickInvertX + + + + 145 + + + + selectDevice: + + + + 146 + + + + changeSetting: + + + + 151 + + + + changeSetting: + + + + 152 + + + + changeSetting: + + + + 153 + + + + changeSetting: + + + + 154 + + + + changeSetting: + + + + 155 + + + + leftLinked + + + + 169 + + + + rightLinked + + + + 170 + + + + changeSetting: + + + + 171 + + + + changeSetting: + + + + 172 + + + + batteryLevel + + + + 175 + + + + changeSetting: + + + + 196 + + + + leftStickDeadzone + + + + 197 + + + + showDeviceList: + + + + 220 + + + + deviceLister + + + + 226 + + + + powerOff: + + + + 229 + + + + powerOff + + + + 230 + + + + dataSource + + + + 225 + + + + done: + + + + 222 + + + + sheet + + + + 223 + + + + list + + + + 224 + + + + + + 0 + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + 12 + + + + + + PrefPane + + + 6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 98 + + + + + + + + 103 + + + + + + + + 104 + + + + + 105 + + + + + 106 + + + + + 107 + + + + + 108 + + + + + 109 + + + + + 110 + + + + + 111 + + + + + 112 + + + + + 114 + + + + + + + + 115 + + + + + + + + 116 + + + + + + + + 117 + + + + + + + + 120 + + + + + + + + 156 + + + + + + + + 157 + + + + + + + + 158 + + + + + + + + + + + + + 174 + + + + + + + + 177 + + + + + + + + 178 + + + + + 179 + + + + + 180 + + + + + 181 + + + + + 182 + + + + + 184 + + + + + 185 + + + + + 186 + + + + + 193 + + + + + 99 + + + + + + + + + + 102 + + + + + 101 + + + + + 100 + + + + + -3 + + + Application + + + 161 + + + + + + + + 187 + + + + + 163 + + + + + + + + 188 + + + + + 165 + + + + + + + + 189 + + + + + 166 + + + + + + + + 190 + + + + + 167 + + + + + + + + 191 + + + + + 168 + + + + + + + + 192 + + + + + 194 + + + + + + + + 195 + + + + + 198 + + + + + + + + 199 + + + + + 200 + + + + + + DeviceSheet + + + 201 + + + + + + + + + + + 202 + + + + + + + + + + 203 + + + + + 204 + + + + + 205 + + + + + + + + + 207 + + + + + + + + 208 + + + + + + + + 209 + + + + + 211 + + + + + 214 + + + + + + + + 215 + + + + + 216 + + + + + + + + 217 + + + + + 218 + + + + + + + + 219 + + + + + 221 + + + + + 227 + + + + + + + + 228 + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{326, 482}, {595, 304}} + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{349, 211}, {519, 336}} + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + 230 + + + + + DeviceLister + NSObject + + done: + id + + + done: + + done: + id + + + + NSTableView + NSWindow + + + + list + NSTableView + + + sheet + NSWindow + + + + IBProjectSource + ./Classes/DeviceLister.h + + + + MyAnalogStick + NSView + + IBProjectSource + ./Classes/MyAnalogStick.h + + + + MyCentreButtons + NSView + + IBProjectSource + ./Classes/MyCentreButtons.h + + + + MyDigitalStick + NSView + + IBProjectSource + ./Classes/MyDigitalStick.h + + + + MyMainButtons + NSView + + IBProjectSource + ./Classes/MyMainButtons.h + + + + MyShoulderButton + NSView + + IBProjectSource + ./Classes/MyShoulderButton.h + + + + NSPreferencePane + NSObject + + NSView + NSView + NSView + NSWindow + + + + _firstKeyView + NSView + + + _initialKeyView + NSView + + + _lastKeyView + NSView + + + _window + NSWindow + + + + IBProjectSource + ./Classes/NSPreferencePane.h + + + + Pref360ControlPref + NSPreferencePane + + id + id + + + + powerOff: + id + + + showDeviceList: + id + + + + NSImageView + MyCentreButtons + NSPopUpButton + DeviceLister + MyDigitalStick + NSButton + MyShoulderButton + MyAnalogStick + NSSlider + NSButton + NSButton + NSProgressIndicator + NSButton + MyMainButtons + NSButton + MyShoulderButton + MyAnalogStick + NSSlider + NSButton + NSButton + NSProgressIndicator + + + + batteryLevel + NSImageView + + + centreButtons + MyCentreButtons + + + deviceList + NSPopUpButton + + + deviceLister + DeviceLister + + + digiStick + MyDigitalStick + + + leftLinked + NSButton + + + leftShoulder + MyShoulderButton + + + leftStick + MyAnalogStick + + + leftStickDeadzone + NSSlider + + + leftStickInvertX + NSButton + + + leftStickInvertY + NSButton + + + leftTrigger + NSProgressIndicator + + + powerOff + NSButton + + + rightButtons + MyMainButtons + + + rightLinked + NSButton + + + rightShoulder + MyShoulderButton + + + rightStick + MyAnalogStick + + + rightStickDeadzone + NSSlider + + + rightStickInvertX + NSButton + + + rightStickInvertY + NSButton + + + rightTrigger + NSProgressIndicator + + + + IBProjectSource + ./Classes/Pref360ControlPref.h + + + + + 0 + IBCocoaFramework + + com.apple.InterfaceBuilder.CocoaPlugin.macosx + + + YES + 3 + + {11, 11} + {10, 3} + {15, 15} + {32, 24} + + + diff --git a/Pref360Control/English.lproj/Pref360ControlPref.nib/keyedobjects.nib b/Pref360Control/English.lproj/Pref360ControlPref.nib/keyedobjects.nib new file mode 100644 index 00000000..00668ec8 Binary files /dev/null and b/Pref360Control/English.lproj/Pref360ControlPref.nib/keyedobjects.nib differ diff --git a/Pref360Control/Info.plist b/Pref360Control/Info.plist new file mode 100644 index 00000000..29c92739 --- /dev/null +++ b/Pref360Control/Info.plist @@ -0,0 +1,34 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + Pref360Control + CFBundleIconFile + + CFBundleIdentifier + com.mice.driver.360Controller.Prefs + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + NSMainNibFile + Pref360ControlPref + NSPrefPaneIconFile + Pref360ControlPref.tiff + NSPrincipalClass + Pref360ControlPref + CFBundleName + XBox 360 Controllers + NSPrefPaneIconLabel + Xbox 360\nControllers + + diff --git a/Pref360Control/MyAnalogStick.h b/Pref360Control/MyAnalogStick.h new file mode 100644 index 00000000..a95fdd23 --- /dev/null +++ b/Pref360Control/MyAnalogStick.h @@ -0,0 +1,39 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + MyAnalogStick.h - declaration of analog stick view + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#import + +@interface MyAnalogStick : NSView +{ + int deadzone; + int x,y; + BOOL pressed,linked; +} + +- (void)setDeadzone:(int)pos; +- (void)setPositionX:(int)xPos y:(int)yPos; +- (void)setPositionX:(int)xPos; +- (void)setPositionY:(int)xPos; +- (void)setPressed:(BOOL)pressedState; +- (void)setLinked:(BOOL)linkedState; + +@end diff --git a/Pref360Control/MyAnalogStick.m b/Pref360Control/MyAnalogStick.m new file mode 100644 index 00000000..cfb63924 --- /dev/null +++ b/Pref360Control/MyAnalogStick.m @@ -0,0 +1,133 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + MyAnalogStick.m - implementation of analog stick view + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#import "MyAnalogStick.h" + +#define PRESSED_INSET 5 +#define AREA_INSET 4 + +@implementation MyAnalogStick + +- (id)initWithFrame:(NSRect)frameRect +{ + if ((self = [super initWithFrame:frameRect]) != nil) { + deadzone=0; + x=0; + y=0; + pressed=FALSE; + linked=FALSE; + } + return self; +} + +- (void)drawRect:(NSRect)rect +{ + NSRect area,deadRect,posRect; + + // Compute positions + // Area + area=[self bounds]; + // Deadzone + deadRect.size.width=(deadzone*area.size.width)/32768; + deadRect.size.height=(deadzone*area.size.height)/32768; + deadRect.origin.x=area.origin.x+((area.size.width-deadRect.size.width)/2); + deadRect.origin.y=area.origin.y+((area.size.height-deadRect.size.height)/2); + // Position + posRect.size.width=4; + posRect.size.height=4; + posRect.origin.x=area.origin.x+AREA_INSET+(((x+32768)*(area.size.width-(AREA_INSET*2)))/65536)-(posRect.size.width/2); + posRect.origin.y=area.origin.y+area.size.height-AREA_INSET-(((y+32768)*(area.size.height-(AREA_INSET*2)))/65536)-(posRect.size.height/2); + // Draw border + NSDrawLightBezel(area,area); + // Draw pressed state + if(pressed) { + NSRect pressArea; + + pressArea=area; + pressArea.origin.x+=PRESSED_INSET; + pressArea.origin.y+=PRESSED_INSET; + pressArea.size.width-=PRESSED_INSET*2; + pressArea.size.height-=PRESSED_INSET*2; + [[NSColor blackColor] set]; + NSRectFill(pressArea); + } + // Draw deadzone + if(deadzone!=0) { + [[NSColor redColor] set]; + if(linked) NSFrameRect(deadRect); + else { + NSRect trueRect; + + trueRect=deadRect; + trueRect.origin.x=area.origin.x; + trueRect.size.width=area.size.width; + NSFrameRect(trueRect); + trueRect=deadRect; + trueRect.origin.y=area.origin.y; + trueRect.size.height=area.size.height; + NSFrameRect(trueRect); + } + } + // Draw position + if(pressed) [[NSColor whiteColor] set]; + else [[NSColor blackColor] set]; + NSRectFill(posRect); +} + +- (void)setDeadzone:(int)pos +{ + deadzone=pos; + [self setNeedsDisplay:YES]; +} + +- (void)setPositionX:(int)xPos y:(int)yPos +{ + x=xPos; + y=yPos; + [self setNeedsDisplay:YES]; +} + +- (void)setPositionX:(int)xPos +{ + x=xPos; + [self setNeedsDisplay:YES]; +} + +- (void)setPositionY:(int)yPos +{ + y=yPos; + [self setNeedsDisplay:YES]; +} + +- (void)setPressed:(BOOL)pressedState +{ + pressed=pressedState; + [self setNeedsDisplay:YES]; +} + +- (void)setLinked:(BOOL)linkedState +{ + linked=linkedState; + [self setNeedsDisplay:YES]; +} + +@end diff --git a/Pref360Control/MyCentreButtons.h b/Pref360Control/MyCentreButtons.h new file mode 100644 index 00000000..97168d5d --- /dev/null +++ b/Pref360Control/MyCentreButtons.h @@ -0,0 +1,34 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + MyCentreButtons.h - definition of view to draw the central buttons + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#import + +@interface MyCentreButtons : NSView +{ + BOOL back,start,appSpecific; +} + +- (void)setBack:(BOOL)bBack; +- (void)setStart:(BOOL)bStart; +- (void)setSpecific:(BOOL)bSpecific; + +@end diff --git a/Pref360Control/MyCentreButtons.m b/Pref360Control/MyCentreButtons.m new file mode 100644 index 00000000..663ace14 --- /dev/null +++ b/Pref360Control/MyCentreButtons.m @@ -0,0 +1,95 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + MyCentreButtons.m - implementation of central button view + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/#import "MyCentreButtons.h" + +@implementation MyCentreButtons + +- (id)initWithFrame:(NSRect)frameRect +{ + if ((self = [super initWithFrame:frameRect]) != nil) { + back=start=appSpecific=FALSE; + } + return self; +} + +- (void)drawButton:(NSString*)button inRectangle:(NSRect)rect pressed:(BOOL)down +{ + NSBezierPath *path; + NSSize size; + NSDictionary *attributes; + NSPoint point; + NSColor *colour; + + // Draw circle + path=[NSBezierPath bezierPathWithOvalInRect:rect]; + colour=[NSColor blackColor]; + [colour set]; + if(down) { + [path fill]; + colour=[NSColor whiteColor]; + } else [path stroke]; + // Draw text + attributes=[NSDictionary dictionaryWithObject:colour forKey:NSForegroundColorAttributeName]; + size=[button sizeWithAttributes:attributes]; + point.x=rect.origin.x+((rect.size.width-size.width)/2); + point.y=rect.origin.y+((rect.size.height-size.height)/2); + [button drawAtPoint:point withAttributes:attributes]; +} + +- (void)drawRect:(NSRect)rect +{ + NSRect area,button; + + area=[self bounds]; + button.size.height=area.size.height/2; + button.size.width=area.size.width/4; + button.origin.x=area.origin.x; + button.origin.y=area.origin.y+((area.size.height-button.size.height)/2); + [self drawButton:@"Back" inRectangle:button pressed:back]; + button.origin.x=area.origin.x+area.size.width-button.size.width; + [self drawButton:@"Start" inRectangle:button pressed:start]; + button.size.height=area.size.height-2; + button.size.width=button.size.height; + button.origin.x=area.origin.x+((area.size.width-button.size.width)/2); + button.origin.y=area.origin.y+1; + [self drawButton:@"" inRectangle:button pressed:appSpecific]; +} + +- (void)setBack:(BOOL)bBack +{ + back=bBack; + [self setNeedsDisplay:TRUE]; +} + +- (void)setStart:(BOOL)bStart +{ + start=bStart; + [self setNeedsDisplay:TRUE]; +} + +- (void)setSpecific:(BOOL)bSpecific +{ + appSpecific=bSpecific; + [self setNeedsDisplay:TRUE]; +} + +@end diff --git a/Pref360Control/MyDigitalStick.h b/Pref360Control/MyDigitalStick.h new file mode 100644 index 00000000..f8ac4254 --- /dev/null +++ b/Pref360Control/MyDigitalStick.h @@ -0,0 +1,36 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + MyDigitalStick.h - declaration of view to draw digital stick view + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#import + +@interface MyDigitalStick : NSView +{ + NSBezierPath *up,*down,*left,*right; + BOOL bUp,bDown,bLeft,bRight; +} + +- (void)setUp:(BOOL)upState; +- (void)setDown:(BOOL)downState; +- (void)setLeft:(BOOL)leftState; +- (void)setRight:(BOOL)rightState; + +@end diff --git a/Pref360Control/MyDigitalStick.m b/Pref360Control/MyDigitalStick.m new file mode 100644 index 00000000..3be6b1ab --- /dev/null +++ b/Pref360Control/MyDigitalStick.m @@ -0,0 +1,132 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + MyDigitalStick.m - implementation of digital stick view + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#import "MyDigitalStick.h" + +#define INSET_AMOUNT 10 + +@implementation MyDigitalStick + +- (NSBezierPath*)makeTriangle:(int)start inRectangle:(NSRect)rect; +{ + NSBezierPath *path; + NSPoint centre,point; + const int mult[][2]={ + {0,0}, + {1,0}, + {1,1}, + {0,1}, + {0,0} + }; + + // Find central part + centre.x=rect.origin.x+(rect.size.width/2); + centre.y=rect.origin.y+(rect.size.height/2); + // Create path + path=[NSBezierPath bezierPath]; + // Make triangle + [path moveToPoint:centre]; + point.x=rect.origin.x+(rect.size.width*mult[start][0]); + point.y=rect.origin.y+(rect.size.height*mult[start][1]); + [path lineToPoint:point]; + point.x=rect.origin.x+(rect.size.width*mult[start+1][0]); + point.y=rect.origin.y+(rect.size.height*mult[start+1][1]); + [path lineToPoint:point]; + [path closePath]; + // Done + return [path retain]; +} + +- (id)initWithFrame:(NSRect)frameRect +{ + if ((self = [super initWithFrame:frameRect]) != nil) { + NSRect rect,triangle; + + bUp=bDown=bLeft=bRight=FALSE; + rect=[self bounds]; + triangle.origin.x+=INSET_AMOUNT; + triangle.origin.y+=INSET_AMOUNT; + triangle.size.width-=INSET_AMOUNT*2; + triangle.size.height-=INSET_AMOUNT*2; + triangle.size.width=rect.size.width/3; + triangle.size.height=rect.size.height/3; + triangle.origin.y=rect.origin.y+(triangle.size.height*2); + triangle.origin.x=rect.origin.x+triangle.size.width; + up=[self makeTriangle:0 inRectangle:triangle]; + triangle.origin.y=rect.origin.y; + down=[self makeTriangle:2 inRectangle:triangle]; + triangle.origin.y=rect.origin.y+triangle.size.height; + triangle.origin.x=rect.origin.x; + left=[self makeTriangle:1 inRectangle:triangle]; + triangle.origin.x=rect.origin.x+(triangle.size.width*2); + right=[self makeTriangle:3 inRectangle:triangle]; + } + return self; +} + +- (void)dealloc +{ + [up release]; + [down release]; + [left release]; + [right release]; + [super dealloc]; +} + +- (void)drawRect:(NSRect)rect +{ + NSRect area; + + area=[self bounds]; + NSDrawLightBezel(area,area); + [[NSColor blackColor] set]; + if(bUp) [up fill]; + if(bDown) [down fill]; + if(bLeft) [left fill]; + if(bRight) [right fill]; +} + +- (void)setUp:(BOOL)upState +{ + bUp=upState; + [self setNeedsDisplay:TRUE]; +} + +- (void)setDown:(BOOL)downState +{ + bDown=downState; + [self setNeedsDisplay:TRUE]; +} + +- (void)setLeft:(BOOL)leftState +{ + bLeft=leftState; + [self setNeedsDisplay:TRUE]; +} + +- (void)setRight:(BOOL)rightState +{ + bRight=rightState; + [self setNeedsDisplay:TRUE]; +} + +@end diff --git a/Pref360Control/MyMainButtons.h b/Pref360Control/MyMainButtons.h new file mode 100644 index 00000000..30244113 --- /dev/null +++ b/Pref360Control/MyMainButtons.h @@ -0,0 +1,35 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + MyMainButtons.h - declaration of A/B/X/Y button view + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#import + +@interface MyMainButtons : NSView +{ + BOOL a,b,x,y; +} + +- (void)setA:(BOOL)aVal; +- (void)setB:(BOOL)bVal; +- (void)setX:(BOOL)xVal; +- (void)setY:(BOOL)yVal; + +@end diff --git a/Pref360Control/MyMainButtons.m b/Pref360Control/MyMainButtons.m new file mode 100644 index 00000000..4d1f6f73 --- /dev/null +++ b/Pref360Control/MyMainButtons.m @@ -0,0 +1,119 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + MyMainButtons.m - implementation of A/B/X/Y button view + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#import "MyMainButtons.h" + +#define MINI_OFFSET 2 + +@implementation MyMainButtons + +- (id)initWithFrame:(NSRect)frameRect +{ + if ((self = [super initWithFrame:frameRect]) != nil) { + a=b=x=y=FALSE; + } + return self; +} + +- (void)drawButton:(NSString*)button inRectangle:(NSRect)rect pressed:(BOOL)down +{ + NSBezierPath *path; + NSSize size; + NSDictionary *attributes; + NSPoint point; + NSColor *colour; + NSRect bling; + + // Draw circle + path=[NSBezierPath bezierPathWithOvalInRect:rect]; + if(down) { + [path fill]; +// colour=[NSColor whiteColor]; + } else { + [path stroke]; +// colour=[NSColor blackColor]; + } + colour=[NSColor blackColor]; + bling=rect; + bling.origin.x-=1; + bling.origin.y-=1; + bling.size.width+=2; + bling.size.height+=2; + path=[NSBezierPath bezierPathWithOvalInRect:bling]; + [colour set]; + [path stroke]; + // Draw text + attributes=[NSDictionary dictionaryWithObject:colour forKey:NSForegroundColorAttributeName]; + size=[button sizeWithAttributes:attributes]; + point.x=rect.origin.x+((rect.size.width-size.width)/2); + point.y=rect.origin.y+((rect.size.height-size.height)/2); + [button drawAtPoint:point withAttributes:attributes]; +} + +- (void)drawRect:(NSRect)rect +{ + NSRect area,bit; + + area=[self bounds]; + bit.size.width=area.size.width/3; + bit.size.height=area.size.height/3; + bit.origin.x=area.origin.x+bit.size.width; + bit.origin.y=area.origin.y+(bit.size.height*2)-MINI_OFFSET; + [[NSColor yellowColor] set]; + [self drawButton:@"Y" inRectangle:bit pressed:y]; + bit.origin.y=area.origin.y+MINI_OFFSET; + [[NSColor greenColor] set]; + [self drawButton:@"A" inRectangle:bit pressed:a]; + bit.origin.y=area.origin.y+bit.size.height; + bit.origin.x=area.origin.x+MINI_OFFSET; + [[NSColor blueColor] set]; + [self drawButton:@"X" inRectangle:bit pressed:x]; + bit.origin.x=area.origin.x+(bit.size.width*2)-MINI_OFFSET; + [[NSColor redColor] set]; + [self drawButton:@"B" inRectangle:bit pressed:b]; +} + +- (void)setA:(BOOL)aVal +{ + a=aVal; + [self setNeedsDisplay:TRUE]; +} + +- (void)setB:(BOOL)bVal +{ + b=bVal; + [self setNeedsDisplay:TRUE]; +} + +- (void)setX:(BOOL)xVal +{ + x=xVal; + [self setNeedsDisplay:TRUE]; +} + +- (void)setY:(BOOL)yVal +{ + y=yVal; + [self setNeedsDisplay:TRUE]; +} + +@end diff --git a/Pref360Control/MyShoulderButton.h b/Pref360Control/MyShoulderButton.h new file mode 100644 index 00000000..d4523d94 --- /dev/null +++ b/Pref360Control/MyShoulderButton.h @@ -0,0 +1,32 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + MyShoulderButton.h - simple button view declaration + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#import + +@interface MyShoulderButton : NSView +{ + BOOL pressed; +} + +- (void)setPressed:(BOOL)b; + +@end diff --git a/Pref360Control/MyShoulderButton.m b/Pref360Control/MyShoulderButton.m new file mode 100644 index 00000000..829db270 --- /dev/null +++ b/Pref360Control/MyShoulderButton.m @@ -0,0 +1,59 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + MyShoulderButton.m - implementation of simple button view + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#import "MyShoulderButton.h" + +#define INSET_AMOUNT 2 + +@implementation MyShoulderButton + +- (id)initWithFrame:(NSRect)frameRect +{ + if ((self = [super initWithFrame:frameRect]) != nil) { + pressed=FALSE; + } + return self; +} + +- (void)drawRect:(NSRect)rect +{ + NSRect area; + + area=[self bounds]; + NSDrawLightBezel(area,area); + if(pressed) { + area.origin.x+=INSET_AMOUNT; + area.origin.y+=INSET_AMOUNT; + area.size.width-=INSET_AMOUNT*2; + area.size.height-=INSET_AMOUNT*2; + [[NSColor blueColor] set]; + NSRectFill(area); + } +} + +- (void)setPressed:(BOOL)b +{ + pressed=b; + [self setNeedsDisplay:TRUE]; +} + +@end diff --git a/Pref360Control/Pref360Control.xcodeproj/project.pbxproj b/Pref360Control/Pref360Control.xcodeproj/project.pbxproj new file mode 100644 index 00000000..f50d2a06 --- /dev/null +++ b/Pref360Control/Pref360Control.xcodeproj/project.pbxproj @@ -0,0 +1,507 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 45; + objects = { + +/* Begin PBXBuildFile section */ + 3B04BE7313763D04005FA9F8 /* DeviceLister.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B04BE7113763D04005FA9F8 /* DeviceLister.h */; }; + 3B04BE7413763D04005FA9F8 /* DeviceLister.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B04BE7213763D04005FA9F8 /* DeviceLister.m */; }; + 3B04BEA61376416D005FA9F8 /* DriverTool in Resources */ = {isa = PBXBuildFile; fileRef = 3B04BEA51376416D005FA9F8 /* DriverTool */; }; + 3B47D9ED0B93C2BF00F200B8 /* battNone.tif in Resources */ = {isa = PBXBuildFile; fileRef = 3B47D9EC0B93C2BF00F200B8 /* battNone.tif */; }; + 3B47D9F20B93C31400F200B8 /* batt1.tif in Resources */ = {isa = PBXBuildFile; fileRef = 3B47D9EE0B93C31400F200B8 /* batt1.tif */; }; + 3B47D9F30B93C31400F200B8 /* batt0.tif in Resources */ = {isa = PBXBuildFile; fileRef = 3B47D9EF0B93C31400F200B8 /* batt0.tif */; }; + 3B47D9F40B93C31400F200B8 /* batt3.tif in Resources */ = {isa = PBXBuildFile; fileRef = 3B47D9F00B93C31400F200B8 /* batt3.tif */; }; + 3B47D9F50B93C31400F200B8 /* batt2.tif in Resources */ = {isa = PBXBuildFile; fileRef = 3B47D9F10B93C31400F200B8 /* batt2.tif */; }; + 3B86987F0CE2A22100283CEC /* ControlPrefs.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B86987D0CE2A22100283CEC /* ControlPrefs.h */; }; + 3B8698800CE2A22100283CEC /* ControlPrefs.m in Sources */ = {isa = PBXBuildFile; fileRef = 3B86987E0CE2A22100283CEC /* ControlPrefs.m */; }; + 3B8B91321376FC120047D446 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B8B91311376FC120047D446 /* Security.framework */; }; + 3BBEAB01096B2C4C00F2E37B /* MyAnalogStick.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BBEAAFF096B2C4C00F2E37B /* MyAnalogStick.h */; }; + 3BBEAB02096B2C4C00F2E37B /* MyAnalogStick.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BBEAB00096B2C4C00F2E37B /* MyAnalogStick.m */; }; + 3BBEAB05096B2C5200F2E37B /* MyCentreButtons.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BBEAB03096B2C5200F2E37B /* MyCentreButtons.m */; }; + 3BBEAB06096B2C5200F2E37B /* MyCentreButtons.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BBEAB04096B2C5200F2E37B /* MyCentreButtons.h */; }; + 3BBEAB09096B2C5600F2E37B /* MyDigitalStick.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BBEAB07096B2C5600F2E37B /* MyDigitalStick.m */; }; + 3BBEAB0A096B2C5600F2E37B /* MyDigitalStick.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BBEAB08096B2C5600F2E37B /* MyDigitalStick.h */; }; + 3BBEAB0D096B2C5B00F2E37B /* MyMainButtons.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BBEAB0B096B2C5B00F2E37B /* MyMainButtons.h */; }; + 3BBEAB0E096B2C5B00F2E37B /* MyMainButtons.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BBEAB0C096B2C5B00F2E37B /* MyMainButtons.m */; }; + 3BBEAB11096B2C6000F2E37B /* MyShoulderButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BBEAB0F096B2C6000F2E37B /* MyShoulderButton.h */; }; + 3BBEAB12096B2C6000F2E37B /* MyShoulderButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BBEAB10096B2C6000F2E37B /* MyShoulderButton.m */; }; + 3BBEAB2D096B6EDE00F2E37B /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BBEAB2C096B6EDE00F2E37B /* IOKit.framework */; }; + 3BC41F32096C85CB00664A42 /* DeviceItem.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BC41F30096C85CB00664A42 /* DeviceItem.h */; }; + 3BC41F33096C85CB00664A42 /* DeviceItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 3BC41F31096C85CB00664A42 /* DeviceItem.m */; }; + 3BC41F47096C8D0300664A42 /* ForceFeedback.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BC41F46096C8D0300664A42 /* ForceFeedback.framework */; }; + 8D202CEA0486D31800D8A456 /* Pref360Control_Prefix.pch in Headers */ = {isa = PBXBuildFile; fileRef = 32DBCFA20370C41700C91783 /* Pref360Control_Prefix.pch */; }; + 8D202CEB0486D31800D8A456 /* Pref360ControlPref.h in Headers */ = {isa = PBXBuildFile; fileRef = F506C03C013D9D7901CA16C8 /* Pref360ControlPref.h */; }; + 8D202CED0486D31800D8A456 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C167DFE841241C02AAC07 /* InfoPlist.strings */; }; + 8D202CEE0486D31800D8A456 /* Pref360ControlPref.tiff in Resources */ = {isa = PBXBuildFile; fileRef = F506C040013D9D8001CA16C8 /* Pref360ControlPref.tiff */; }; + 8D202CEF0486D31800D8A456 /* Pref360ControlPref.nib in Resources */ = {isa = PBXBuildFile; fileRef = F506C042013D9D8C01CA16C8 /* Pref360ControlPref.nib */; }; + 8D202CF10486D31800D8A456 /* Pref360ControlPref.m in Sources */ = {isa = PBXBuildFile; fileRef = F506C03D013D9D7901CA16C8 /* Pref360ControlPref.m */; }; + 8D202CF30486D31800D8A456 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */; }; + 8D202CF40486D31800D8A456 /* PreferencePanes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F506C035013D953901CA16C8 /* PreferencePanes.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 089C1672FE841209C02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; + 089C167EFE841241C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + 089C167FFE841241C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; + 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; + 32DBCFA20370C41700C91783 /* Pref360Control_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Pref360Control_Prefix.pch; sourceTree = ""; }; + 3B04BE7113763D04005FA9F8 /* DeviceLister.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeviceLister.h; sourceTree = ""; }; + 3B04BE7213763D04005FA9F8 /* DeviceLister.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DeviceLister.m; sourceTree = ""; }; + 3B04BEA51376416D005FA9F8 /* DriverTool */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; name = DriverTool; path = ../DriverTool/build/Release/DriverTool; sourceTree = SOURCE_ROOT; }; + 3B47D9EC0B93C2BF00F200B8 /* battNone.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = battNone.tif; sourceTree = ""; }; + 3B47D9EE0B93C31400F200B8 /* batt1.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = batt1.tif; sourceTree = ""; }; + 3B47D9EF0B93C31400F200B8 /* batt0.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = batt0.tif; sourceTree = ""; }; + 3B47D9F00B93C31400F200B8 /* batt3.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = batt3.tif; sourceTree = ""; }; + 3B47D9F10B93C31400F200B8 /* batt2.tif */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = batt2.tif; sourceTree = ""; }; + 3B86987D0CE2A22100283CEC /* ControlPrefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ControlPrefs.h; path = ../360Daemon/ControlPrefs.h; sourceTree = SOURCE_ROOT; }; + 3B86987E0CE2A22100283CEC /* ControlPrefs.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ControlPrefs.m; path = ../360Daemon/ControlPrefs.m; sourceTree = SOURCE_ROOT; }; + 3B8B91311376FC120047D446 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + 3BBEAAFF096B2C4C00F2E37B /* MyAnalogStick.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MyAnalogStick.h; sourceTree = ""; }; + 3BBEAB00096B2C4C00F2E37B /* MyAnalogStick.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = MyAnalogStick.m; sourceTree = ""; }; + 3BBEAB03096B2C5200F2E37B /* MyCentreButtons.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = MyCentreButtons.m; sourceTree = ""; }; + 3BBEAB04096B2C5200F2E37B /* MyCentreButtons.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MyCentreButtons.h; sourceTree = ""; }; + 3BBEAB07096B2C5600F2E37B /* MyDigitalStick.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = MyDigitalStick.m; sourceTree = ""; }; + 3BBEAB08096B2C5600F2E37B /* MyDigitalStick.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MyDigitalStick.h; sourceTree = ""; }; + 3BBEAB0B096B2C5B00F2E37B /* MyMainButtons.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MyMainButtons.h; sourceTree = ""; }; + 3BBEAB0C096B2C5B00F2E37B /* MyMainButtons.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = MyMainButtons.m; sourceTree = ""; }; + 3BBEAB0F096B2C6000F2E37B /* MyShoulderButton.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = MyShoulderButton.h; sourceTree = ""; }; + 3BBEAB10096B2C6000F2E37B /* MyShoulderButton.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = MyShoulderButton.m; sourceTree = ""; }; + 3BBEAB2C096B6EDE00F2E37B /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = ""; }; + 3BC41F30096C85CB00664A42 /* DeviceItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeviceItem.h; sourceTree = ""; }; + 3BC41F31096C85CB00664A42 /* DeviceItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DeviceItem.m; sourceTree = ""; }; + 3BC41F46096C8D0300664A42 /* ForceFeedback.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ForceFeedback.framework; path = /System/Library/Frameworks/ForceFeedback.framework; sourceTree = ""; }; + 8D202CF70486D31800D8A456 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 8D202CF80486D31800D8A456 /* Pref360Control.prefPane */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Pref360Control.prefPane; sourceTree = BUILT_PRODUCTS_DIR; }; + F506C035013D953901CA16C8 /* PreferencePanes.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PreferencePanes.framework; path = /System/Library/Frameworks/PreferencePanes.framework; sourceTree = ""; }; + F506C03C013D9D7901CA16C8 /* Pref360ControlPref.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Pref360ControlPref.h; sourceTree = ""; }; + F506C03D013D9D7901CA16C8 /* Pref360ControlPref.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Pref360ControlPref.m; sourceTree = ""; }; + F506C040013D9D8001CA16C8 /* Pref360ControlPref.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = Pref360ControlPref.tiff; sourceTree = ""; }; + F506C043013D9D8C01CA16C8 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/Pref360ControlPref.nib; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8D202CF20486D31800D8A456 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D202CF30486D31800D8A456 /* Cocoa.framework in Frameworks */, + 8D202CF40486D31800D8A456 /* PreferencePanes.framework in Frameworks */, + 3BBEAB2D096B6EDE00F2E37B /* IOKit.framework in Frameworks */, + 3BC41F47096C8D0300664A42 /* ForceFeedback.framework in Frameworks */, + 3B8B91321376FC120047D446 /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 089C166AFE841209C02AAC07 /* Pref360Control */ = { + isa = PBXGroup; + children = ( + 08FB77AFFE84173DC02AAC07 /* Classes */, + 32DBCFA10370C40200C91783 /* Other Sources */, + 089C167CFE841241C02AAC07 /* Resources */, + 089C1671FE841209C02AAC07 /* Frameworks and Libraries */, + 19C28FB8FE9D52D311CA2CBB /* Products */, + ); + name = Pref360Control; + sourceTree = ""; + }; + 089C1671FE841209C02AAC07 /* Frameworks and Libraries */ = { + isa = PBXGroup; + children = ( + 1058C7ACFEA557BF11CA2CBB /* Linked Frameworks */, + 1058C7AEFEA557BF11CA2CBB /* Other Frameworks */, + ); + name = "Frameworks and Libraries"; + sourceTree = ""; + }; + 089C167CFE841241C02AAC07 /* Resources */ = { + isa = PBXGroup; + children = ( + 3B04BEA51376416D005FA9F8 /* DriverTool */, + 8D202CF70486D31800D8A456 /* Info.plist */, + 089C167DFE841241C02AAC07 /* InfoPlist.strings */, + F506C040013D9D8001CA16C8 /* Pref360ControlPref.tiff */, + F506C042013D9D8C01CA16C8 /* Pref360ControlPref.nib */, + 3B47D9EC0B93C2BF00F200B8 /* battNone.tif */, + 3B47D9EF0B93C31400F200B8 /* batt0.tif */, + 3B47D9EE0B93C31400F200B8 /* batt1.tif */, + 3B47D9F10B93C31400F200B8 /* batt2.tif */, + 3B47D9F00B93C31400F200B8 /* batt3.tif */, + ); + name = Resources; + sourceTree = ""; + }; + 08FB77AFFE84173DC02AAC07 /* Classes */ = { + isa = PBXGroup; + children = ( + 3B86987D0CE2A22100283CEC /* ControlPrefs.h */, + 3B86987E0CE2A22100283CEC /* ControlPrefs.m */, + F506C03C013D9D7901CA16C8 /* Pref360ControlPref.h */, + F506C03D013D9D7901CA16C8 /* Pref360ControlPref.m */, + 3BBEAAFF096B2C4C00F2E37B /* MyAnalogStick.h */, + 3BBEAB00096B2C4C00F2E37B /* MyAnalogStick.m */, + 3BBEAB04096B2C5200F2E37B /* MyCentreButtons.h */, + 3BBEAB03096B2C5200F2E37B /* MyCentreButtons.m */, + 3BBEAB08096B2C5600F2E37B /* MyDigitalStick.h */, + 3BBEAB07096B2C5600F2E37B /* MyDigitalStick.m */, + 3BBEAB0B096B2C5B00F2E37B /* MyMainButtons.h */, + 3BBEAB0C096B2C5B00F2E37B /* MyMainButtons.m */, + 3BBEAB0F096B2C6000F2E37B /* MyShoulderButton.h */, + 3BBEAB10096B2C6000F2E37B /* MyShoulderButton.m */, + 3BC41F30096C85CB00664A42 /* DeviceItem.h */, + 3BC41F31096C85CB00664A42 /* DeviceItem.m */, + 3B04BE7113763D04005FA9F8 /* DeviceLister.h */, + 3B04BE7213763D04005FA9F8 /* DeviceLister.m */, + ); + name = Classes; + sourceTree = ""; + }; + 1058C7ACFEA557BF11CA2CBB /* Linked Frameworks */ = { + isa = PBXGroup; + children = ( + 3BC41F46096C8D0300664A42 /* ForceFeedback.framework */, + 3BBEAB2C096B6EDE00F2E37B /* IOKit.framework */, + 1058C7ADFEA557BF11CA2CBB /* Cocoa.framework */, + F506C035013D953901CA16C8 /* PreferencePanes.framework */, + 3B8B91311376FC120047D446 /* Security.framework */, + ); + name = "Linked Frameworks"; + sourceTree = ""; + }; + 1058C7AEFEA557BF11CA2CBB /* Other Frameworks */ = { + isa = PBXGroup; + children = ( + 089C1672FE841209C02AAC07 /* Foundation.framework */, + 089C167FFE841241C02AAC07 /* AppKit.framework */, + ); + name = "Other Frameworks"; + sourceTree = ""; + }; + 19C28FB8FE9D52D311CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8D202CF80486D31800D8A456 /* Pref360Control.prefPane */, + ); + name = Products; + sourceTree = ""; + }; + 32DBCFA10370C40200C91783 /* Other Sources */ = { + isa = PBXGroup; + children = ( + 32DBCFA20370C41700C91783 /* Pref360Control_Prefix.pch */, + ); + name = "Other Sources"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 8D202CE90486D31800D8A456 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D202CEA0486D31800D8A456 /* Pref360Control_Prefix.pch in Headers */, + 8D202CEB0486D31800D8A456 /* Pref360ControlPref.h in Headers */, + 3BBEAB01096B2C4C00F2E37B /* MyAnalogStick.h in Headers */, + 3BBEAB06096B2C5200F2E37B /* MyCentreButtons.h in Headers */, + 3BBEAB0A096B2C5600F2E37B /* MyDigitalStick.h in Headers */, + 3BBEAB0D096B2C5B00F2E37B /* MyMainButtons.h in Headers */, + 3BBEAB11096B2C6000F2E37B /* MyShoulderButton.h in Headers */, + 3BC41F32096C85CB00664A42 /* DeviceItem.h in Headers */, + 3B86987F0CE2A22100283CEC /* ControlPrefs.h in Headers */, + 3B04BE7313763D04005FA9F8 /* DeviceLister.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 8D202CE80486D31800D8A456 /* Pref360Control */ = { + isa = PBXNativeTarget; + buildConfigurationList = 3BBDC6A5097946B50023AAD8 /* Build configuration list for PBXNativeTarget "Pref360Control" */; + buildPhases = ( + 8D202CE90486D31800D8A456 /* Headers */, + 8D202CEC0486D31800D8A456 /* Resources */, + 8D202CF00486D31800D8A456 /* Sources */, + 8D202CF20486D31800D8A456 /* Frameworks */, + 8D202CF50486D31800D8A456 /* Rez */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Pref360Control; + productInstallPath = "$(HOME)/Library/PreferencePanes"; + productName = Pref360Control; + productReference = 8D202CF80486D31800D8A456 /* Pref360Control.prefPane */; + productType = "com.apple.product-type.bundle"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 089C1669FE841209C02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 3BBDC6A9097946B50023AAD8 /* Build configuration list for PBXProject "Pref360Control" */; + compatibilityVersion = "Xcode 3.0"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 089C166AFE841209C02AAC07 /* Pref360Control */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8D202CE80486D31800D8A456 /* Pref360Control */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8D202CEC0486D31800D8A456 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D202CED0486D31800D8A456 /* InfoPlist.strings in Resources */, + 8D202CEE0486D31800D8A456 /* Pref360ControlPref.tiff in Resources */, + 8D202CEF0486D31800D8A456 /* Pref360ControlPref.nib in Resources */, + 3B47D9ED0B93C2BF00F200B8 /* battNone.tif in Resources */, + 3B47D9F20B93C31400F200B8 /* batt1.tif in Resources */, + 3B47D9F30B93C31400F200B8 /* batt0.tif in Resources */, + 3B47D9F40B93C31400F200B8 /* batt3.tif in Resources */, + 3B47D9F50B93C31400F200B8 /* batt2.tif in Resources */, + 3B04BEA61376416D005FA9F8 /* DriverTool in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXRezBuildPhase section */ + 8D202CF50486D31800D8A456 /* Rez */ = { + isa = PBXRezBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXRezBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8D202CF00486D31800D8A456 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D202CF10486D31800D8A456 /* Pref360ControlPref.m in Sources */, + 3BBEAB02096B2C4C00F2E37B /* MyAnalogStick.m in Sources */, + 3BBEAB05096B2C5200F2E37B /* MyCentreButtons.m in Sources */, + 3BBEAB09096B2C5600F2E37B /* MyDigitalStick.m in Sources */, + 3BBEAB0E096B2C5B00F2E37B /* MyMainButtons.m in Sources */, + 3BBEAB12096B2C6000F2E37B /* MyShoulderButton.m in Sources */, + 3BC41F33096C85CB00664A42 /* DeviceItem.m in Sources */, + 3B8698800CE2A22100283CEC /* ControlPrefs.m in Sources */, + 3B04BE7413763D04005FA9F8 /* DeviceLister.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 089C167DFE841241C02AAC07 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 089C167EFE841241C02AAC07 /* English */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + F506C042013D9D8C01CA16C8 /* Pref360ControlPref.nib */ = { + isa = PBXVariantGroup; + children = ( + F506C043013D9D8C01CA16C8 /* English */, + ); + name = Pref360ControlPref.nib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 3BBDC6A6097946B50023AAD8 /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + COPY_PHASE_STRIP = NO; + DEBUGGING_SYMBOLS = YES; + FRAMEWORK_SEARCH_PATHS = ""; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + "GCC_ENABLE_OBJC_GC[arch=x86_64]" = supported; + GCC_ENABLE_TRIGRAPHS = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = Pref360Control_Prefix.pch; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + GCC_WARN_UNKNOWN_PRAGMAS = NO; + HEADER_SEARCH_PATHS = ""; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(HOME)/Library/PreferencePanes"; + LIBRARY_SEARCH_PATHS = ""; + LIBRARY_STYLE = Bundle; + MACOSX_DEPLOYMENT_TARGET = 10.5; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ( + "-bundle", + "-twolevel_namespace", + ); + OTHER_REZFLAGS = ""; + PRODUCT_NAME = Pref360Control; + SDKROOT = ""; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = ( + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + WRAPPER_EXTENSION = prefPane; + ZERO_LINK = YES; + }; + name = Development; + }; + 3BBDC6A7097946B50023AAD8 /* Deployment */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + FRAMEWORK_SEARCH_PATHS = ""; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + "GCC_ENABLE_OBJC_GC[arch=x86_64]" = supported; + GCC_ENABLE_TRIGRAPHS = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = Pref360Control_Prefix.pch; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + GCC_WARN_UNKNOWN_PRAGMAS = NO; + HEADER_SEARCH_PATHS = ""; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(HOME)/Library/PreferencePanes"; + LIBRARY_SEARCH_PATHS = ""; + LIBRARY_STYLE = Bundle; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ( + "-bundle", + "-twolevel_namespace", + ); + OTHER_REZFLAGS = ""; + PRODUCT_NAME = Pref360Control; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = ( + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + WRAPPER_EXTENSION = prefPane; + ZERO_LINK = NO; + }; + name = Deployment; + }; + 3BBDC6A8097946B50023AAD8 /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + FRAMEWORK_SEARCH_PATHS = ""; + "GCC_ENABLE_OBJC_GC[arch=x86_64]" = supported; + GCC_ENABLE_TRIGRAPHS = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = Pref360Control_Prefix.pch; + GCC_WARN_ABOUT_MISSING_PROTOTYPES = NO; + GCC_WARN_FOUR_CHARACTER_CONSTANTS = NO; + GCC_WARN_UNKNOWN_PRAGMAS = NO; + HEADER_SEARCH_PATHS = ""; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(HOME)/Library/PreferencePanes"; + LIBRARY_SEARCH_PATHS = ""; + LIBRARY_STYLE = Bundle; + OTHER_CFLAGS = ""; + OTHER_LDFLAGS = ( + "-bundle", + "-twolevel_namespace", + ); + OTHER_REZFLAGS = ""; + PRODUCT_NAME = Pref360Control; + SECTORDER_FLAGS = ""; + WARNING_CFLAGS = ( + "-Wmost", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + WRAPPER_EXTENSION = prefPane; + }; + name = Default; + }; + 3BBDC6AA097946B50023AAD8 /* Development */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "Developer ID Application: Colin Munro"; + MACOSX_DEPLOYMENT_TARGET = 10.5; + PROVISIONING_PROFILE = ""; + SDKROOT = ""; + }; + name = Development; + }; + 3BBDC6AB097946B50023AAD8 /* Deployment */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + CODE_SIGN_IDENTITY = "Developer ID Application: Colin Munro"; + MACOSX_DEPLOYMENT_TARGET = 10.5; + PROVISIONING_PROFILE = ""; + SDKROOT = ""; + }; + name = Deployment; + }; + 3BBDC6AC097946B50023AAD8 /* Default */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "Developer ID Application: Colin Munro"; + MACOSX_DEPLOYMENT_TARGET = 10.5; + PROVISIONING_PROFILE = ""; + SDKROOT = ""; + }; + name = Default; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 3BBDC6A5097946B50023AAD8 /* Build configuration list for PBXNativeTarget "Pref360Control" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3BBDC6A6097946B50023AAD8 /* Development */, + 3BBDC6A7097946B50023AAD8 /* Deployment */, + 3BBDC6A8097946B50023AAD8 /* Default */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Default; + }; + 3BBDC6A9097946B50023AAD8 /* Build configuration list for PBXProject "Pref360Control" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 3BBDC6AA097946B50023AAD8 /* Development */, + 3BBDC6AB097946B50023AAD8 /* Deployment */, + 3BBDC6AC097946B50023AAD8 /* Default */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Default; + }; +/* End XCConfigurationList section */ + }; + rootObject = 089C1669FE841209C02AAC07 /* Project object */; +} diff --git a/Pref360Control/Pref360ControlPref.h b/Pref360Control/Pref360ControlPref.h new file mode 100644 index 00000000..28f4b81d --- /dev/null +++ b/Pref360Control/Pref360ControlPref.h @@ -0,0 +1,93 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + Pref360ControlPref.h - definition for the pref pane class + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#import + +#import +#import +#import +#import +#import + +#include "MyCentreButtons.h" +#include "MyDigitalStick.h" +#include "MyAnalogStick.h" +#include "MyMainButtons.h" +#include "MyShoulderButton.h" + +@class DeviceLister; + +@interface Pref360ControlPref : NSPreferencePane +{ + // Window components + IBOutlet MyCentreButtons *centreButtons; + IBOutlet NSPopUpButton *deviceList; + IBOutlet MyDigitalStick *digiStick; + IBOutlet MyShoulderButton *leftShoulder; + IBOutlet MyAnalogStick *leftStick; + IBOutlet NSButton *leftLinked; + IBOutlet NSSlider *leftStickDeadzone; + IBOutlet NSButton *leftStickInvertX; + IBOutlet NSButton *leftStickInvertY; + IBOutlet NSProgressIndicator *leftTrigger; + IBOutlet MyMainButtons *rightButtons; + IBOutlet MyShoulderButton *rightShoulder; + IBOutlet MyAnalogStick *rightStick; + IBOutlet NSButton *rightLinked; + IBOutlet NSSlider *rightStickDeadzone; + IBOutlet NSButton *rightStickInvertX; + IBOutlet NSButton *rightStickInvertY; + IBOutlet NSProgressIndicator *rightTrigger; + IBOutlet NSImageView *batteryLevel; + IBOutlet DeviceLister *deviceLister; + IBOutlet NSButton *powerOff; + // Internal info + mach_port_t masterPort; + NSMutableArray *deviceArray; + IOHIDElementCookie axis[6],buttons[15]; + + IOHIDDeviceInterface122 **device; + IOHIDQueueInterface **hidQueue; + FFDeviceObjectReference ffDevice; + io_registry_entry_t registryEntry; + + int largeMotor,smallMotor; + + IONotificationPortRef notifyPort; + CFRunLoopSourceRef notifySource; + io_iterator_t onIteratorWired, offIteratorWired; + io_iterator_t onIteratorWireless, offIteratorWireless; +} + +- (void)mainViewDidLoad; + +- (void)eventQueueFired:(void*)sender withResult:(IOReturn)result; + +- (void)handleDeviceChange; + +- (IBAction)showDeviceList:(id)sender; +- (IBAction)powerOff:(id)sender; + +- (mach_port_t)masterPort; + +@end diff --git a/Pref360Control/Pref360ControlPref.m b/Pref360Control/Pref360ControlPref.m new file mode 100644 index 00000000..3f700a0f --- /dev/null +++ b/Pref360Control/Pref360ControlPref.m @@ -0,0 +1,716 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + Pref360ControlPref.m - main source of the pref pane + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include +#include +#import "Pref360ControlPref.h" +#import "DeviceItem.h" +#import "ControlPrefs.h" +#import "DeviceLister.h" + +#define NO_ITEMS @"No devices found" + +// Passes a C callback back to the Objective C class +static void CallbackFunction(void *target,IOReturn result,void *refCon,void *sender) +{ + if(target!=NULL) [((Pref360ControlPref*)target) eventQueueFired:sender withResult:result]; +} + +// Handle callback for when our device is connected or disconnected. Both events are +// actually handled identically. +static void callbackHandleDevice(void *param,io_iterator_t iterator) +{ + io_service_t object=0; + BOOL update; + + update=FALSE; + while((object=IOIteratorNext(iterator))!=0) { + IOObjectRelease(object); + update=TRUE; + } + if(update) [(Pref360ControlPref*)param handleDeviceChange]; +} + +@implementation Pref360ControlPref + +// Set the pattern on the LEDs +- (void)updateLED:(int)ledIndex +{ + FFEFFESCAPE escape; + unsigned char c; + + if(ffDevice==0) return; + c=ledIndex; + escape.dwSize=sizeof(escape); + escape.dwCommand=0x02; + escape.cbInBuffer=sizeof(c); + escape.lpvInBuffer=&c; + escape.cbOutBuffer=0; + escape.lpvOutBuffer=NULL; + FFDeviceEscape(ffDevice,&escape); +} + +// Enables and disables the rumble motor "override" +- (void)setMotorOverride:(BOOL)enable +{ + FFEFFESCAPE escape; + char c; + + if(ffDevice==0) return; + // If true, the motors will no longer obey any Force Feedback Framework + // effects, and the motors may be controlled directly. False and the + // motors will perform effects but can not be directly controlled. + c=enable?0x01:0x00; + escape.dwSize=sizeof(escape); + escape.dwCommand=0x00; + escape.cbInBuffer=sizeof(c); + escape.lpvInBuffer=&c; + escape.cbOutBuffer=0; + escape.lpvOutBuffer=NULL; + FFDeviceEscape(ffDevice,&escape); +} + +// If the direct rumble control is enabled, this will set the motors +// to the desired speed. +- (void)testMotorsLarge:(unsigned char)large small:(unsigned char)small +{ + FFEFFESCAPE escape; + char c[2]; + + if(ffDevice==0) return; + c[0]=large; + c[1]=small; + escape.dwSize=sizeof(escape); + escape.dwCommand=0x01; + escape.cbInBuffer=sizeof(c); + escape.lpvInBuffer=c; + escape.cbOutBuffer=0; + escape.lpvOutBuffer=NULL; + FFDeviceEscape(ffDevice,&escape); +} + +// Update axis GUI component +- (void)axisChanged:(int)index newValue:(int)value +{ + switch(index) { + case 0: + [leftStick setPositionX:value]; + break; + case 1: + [leftStick setPositionY:value]; + break; + case 2: + [rightStick setPositionX:value]; + break; + case 3: + [rightStick setPositionY:value]; + break; + case 4: + [leftTrigger setDoubleValue:value]; + largeMotor=value; +// [self testMotorsLarge:largeMotor small:smallMotor]; + break; + case 5: + [rightTrigger setDoubleValue:value]; + smallMotor=value; +// [self testMotorsLarge:largeMotor small:smallMotor]; + break; + default: + break; + } +} + +// Update button GUI component +- (void)buttonChanged:(int)index newValue:(int)value +{ + BOOL b; + + b=value!=0; + switch(index) { + case 0: + [rightButtons setA:b]; + break; + case 1: + [rightButtons setB:b]; + break; + case 2: + [rightButtons setX:b]; + break; + case 3: + [rightButtons setY:b]; + break; + case 4: + [leftShoulder setPressed:b]; + break; + case 5: + [rightShoulder setPressed:b]; + break; + case 6: + [leftStick setPressed:b]; + break; + case 7: + [rightStick setPressed:b]; + break; + case 8: + [centreButtons setStart:b]; + break; + case 9: + [centreButtons setBack:b]; + break; + case 10: + [centreButtons setSpecific:b]; + break; + case 11: + [digiStick setUp:b]; + break; + case 12: + [digiStick setDown:b]; + break; + case 13: + [digiStick setLeft:b]; + break; + case 14: + [digiStick setRight:b]; + break; + default: + break; + } +} + +// Handle message from I/O Kit indicating something happened on the device +- (void)eventQueueFired:(void*)sender withResult:(IOReturn)result +{ + AbsoluteTime zeroTime={0,0}; + IOHIDEventStruct event; + BOOL found; + int i; + + if(sender!=hidQueue) return; + while(result==kIOReturnSuccess) { + result=(*hidQueue)->getNextEvent(hidQueue,&event,zeroTime,0); + if(result!=kIOReturnSuccess) continue; + // Check axis + for(i=0,found=FALSE;(i<6)&&(!found);i++) { + if(event.elementCookie==axis[i]) { + [self axisChanged:i newValue:event.value]; + found=TRUE; + } + } + if(found) continue; + // Check buttons + for(i=0,found=FALSE;(i<15)&&(!found);i++) { + if(event.elementCookie==buttons[i]) { + [self buttonChanged:i newValue:event.value]; + found=TRUE; + } + } + if(found) continue; + // Cookie wasn't for us? + } +} + +// Enable input components +- (void)inputEnable:(BOOL)enable +{ + [leftStickDeadzone setEnabled:enable]; + [leftStickInvertX setEnabled:enable]; + [leftStickInvertY setEnabled:enable]; + [leftLinked setEnabled:enable]; + [rightStickDeadzone setEnabled:enable]; + [rightStickInvertX setEnabled:enable]; + [rightStickInvertY setEnabled:enable]; + [rightLinked setEnabled:enable]; +} + +// Reset GUI components +- (void)resetDisplay +{ + NSBundle *bundle; + + [leftStick setPositionX:0 y:0]; + [leftStick setPressed:FALSE]; + [leftStick setDeadzone:0]; + [digiStick setUp:FALSE]; + [digiStick setDown:FALSE]; + [digiStick setLeft:FALSE]; + [digiStick setRight:FALSE]; + [centreButtons setBack:FALSE]; + [centreButtons setSpecific:FALSE]; + [centreButtons setStart:FALSE]; + [rightStick setPositionX:0 y:0]; + [rightStick setPressed:FALSE]; + [rightStick setDeadzone:0]; + [rightButtons setA:FALSE]; + [rightButtons setB:FALSE]; + [rightButtons setX:FALSE]; + [rightButtons setY:FALSE]; + [leftShoulder setPressed:FALSE]; + [leftTrigger setDoubleValue:0]; + [rightShoulder setPressed:FALSE]; + [rightTrigger setDoubleValue:0]; + // Reset inputs + [leftStickDeadzone setIntValue:0]; + [leftStickInvertX setState:NSOffState]; + [leftStickInvertY setState:NSOffState]; + [rightStickDeadzone setIntValue:0]; + [rightStickInvertX setState:NSOffState]; + [rightStickInvertY setState:NSOffState]; + // Disable inputs + [self inputEnable:NO]; + [powerOff setHidden:YES]; + // Hide battery icon + bundle = [NSBundle bundleForClass:[self class]]; + [batteryLevel setImage:[[[NSImage alloc] initByReferencingFile:[bundle pathForResource:@"battNone" ofType:@"tif"]] autorelease]]; +} + +// Stop using the HID device +- (void)stopDevice +{ + if(registryEntry==0) return; +// [self testMotorsLarge:0 small:0]; +// [self setMotorOverride:FALSE]; +// [self updateLED:0x00]; + if(hidQueue!=NULL) { + CFRunLoopSourceRef eventSource; + + (*hidQueue)->stop(hidQueue); + eventSource=(*hidQueue)->getAsyncEventSource(hidQueue); + if((eventSource!=NULL)&&CFRunLoopContainsSource(CFRunLoopGetCurrent(),eventSource,kCFRunLoopCommonModes)) + CFRunLoopRemoveSource(CFRunLoopGetCurrent(),eventSource,kCFRunLoopCommonModes); + (*hidQueue)->Release(hidQueue); + hidQueue=NULL; + } + if(device!=NULL) { + (*device)->close(device); + device=NULL; + } + registryEntry=0; +} + +// Start using a HID device +- (void)startDevice +{ + int i,j; + CFArrayRef elements; + CFDictionaryRef element; + CFTypeRef object; + long number; + IOHIDElementCookie cookie; + long usage,usagePage; + CFRunLoopSourceRef eventSource; + IOReturn ret; + + [self resetDisplay]; + i=(int)[deviceList indexOfSelectedItem]; + if(([deviceArray count]==0)||(i==-1)) { + NSLog(@"No devices found? :( device count==%i, i==%i",(int)[deviceArray count],i); + return; + } + { + DeviceItem *item=[deviceArray objectAtIndex:i]; + + device=[item hidDevice]; + ffDevice=[item ffDevice]; + registryEntry=[item rawDevice]; + } + if((*device)->copyMatchingElements(device,NULL,&elements)!=kIOReturnSuccess) { + NSLog(@"Can't get elements list"); + // Make note of failure? + return; + } + for(i=0;i=1)&&(usage<=15)) { + // Button 1-11 + buttons[usage-1]=cookie; + } + break; + default: + break; + } + } + // Start queue + if((*device)->open(device,0)!=kIOReturnSuccess) { + NSLog(@"Can't open device"); + // Make note of failure? + return; + } + hidQueue=(*device)->allocQueue(device); + if(hidQueue==NULL) { + NSLog(@"Unable to allocate queue"); + // Error? + return; + } + ret=(*hidQueue)->create(hidQueue,0,32); + if(ret!=kIOReturnSuccess) { + NSLog(@"Unable to create the queue"); + // Error? + return; + } + // Create event source + ret=(*hidQueue)->createAsyncEventSource(hidQueue,&eventSource); + if(ret!=kIOReturnSuccess) { + NSLog(@"Unable to create async event source"); + // Error? + return; + } + // Set callback + ret=(*hidQueue)->setEventCallout(hidQueue,CallbackFunction,self,NULL); + if(ret!=kIOReturnSuccess) { + NSLog(@"Unable to set event callback"); + // Error? + return; + } + // Add to runloop + CFRunLoopAddSource(CFRunLoopGetCurrent(),eventSource,kCFRunLoopCommonModes); + // Add some elements + for(i=0;i<6;i++) + (*hidQueue)->addElement(hidQueue,axis[i],0); + for(i=0;i<15;i++) + (*hidQueue)->addElement(hidQueue,buttons[i],0); + // Start + ret=(*hidQueue)->start(hidQueue); + if(ret!=kIOReturnSuccess) { + NSLog(@"Unable to start queue - 0x%.8x",ret); + // Error? + return; + } + // Read existing properties + { +// CFDictionaryRef dict=(CFDictionaryRef)IORegistryEntryCreateCFProperty(registryEntry,CFSTR("DeviceData"),NULL,0); + CFDictionaryRef dict = (CFDictionaryRef)[GetController(GetSerialNumber(registryEntry)) retain]; + if(dict!=0) { + CFBooleanRef boolValue; + CFNumberRef intValue; + + if(CFDictionaryGetValueIfPresent(dict,CFSTR("InvertLeftX"),(void*)&boolValue)) { + [leftStickInvertX setState:CFBooleanGetValue(boolValue)?NSOnState:NSOffState]; + } else NSLog(@"No value for InvertLeftX"); + if(CFDictionaryGetValueIfPresent(dict,CFSTR("InvertLeftY"),(void*)&boolValue)) { + [leftStickInvertY setState:CFBooleanGetValue(boolValue)?NSOnState:NSOffState]; + } else NSLog(@"No value for InvertLeftY"); + if(CFDictionaryGetValueIfPresent(dict,CFSTR("RelativeLeft"),(void*)&boolValue)) { + BOOL enable=CFBooleanGetValue(boolValue); + [leftLinked setState:enable?NSOnState:NSOffState]; + [leftStick setLinked:enable]; + } else NSLog(@"No value for RelativeLeft"); + if(CFDictionaryGetValueIfPresent(dict,CFSTR("DeadzoneLeft"),(void*)&intValue)) { + UInt16 i; + + CFNumberGetValue(intValue,kCFNumberShortType,&i); + [leftStickDeadzone setIntValue:i]; + [leftStick setDeadzone:i]; + } else NSLog(@"No value for DeadzoneLeft"); + if(CFDictionaryGetValueIfPresent(dict,CFSTR("InvertRightX"),(void*)&boolValue)) { + [rightStickInvertX setState:CFBooleanGetValue(boolValue)?NSOnState:NSOffState]; + } else NSLog(@"No value for InvertRightX"); + if(CFDictionaryGetValueIfPresent(dict,CFSTR("InvertRightY"),(void*)&boolValue)) { + [rightStickInvertY setState:CFBooleanGetValue(boolValue)?NSOnState:NSOffState]; + } else NSLog(@"No value for InvertRightY"); + if(CFDictionaryGetValueIfPresent(dict,CFSTR("RelativeRight"),(void*)&boolValue)) { + BOOL enable=CFBooleanGetValue(boolValue); + [rightLinked setState:enable?NSOnState:NSOffState]; + [rightStick setLinked:enable]; + } else NSLog(@"No value for RelativeRight"); + if(CFDictionaryGetValueIfPresent(dict,CFSTR("DeadzoneRight"),(void*)&intValue)) { + UInt16 i; + + CFNumberGetValue(intValue,kCFNumberShortType,&i); + [rightStickDeadzone setIntValue:i]; + [rightStick setDeadzone:i]; + } else NSLog(@"No value for DeadzoneRight"); + CFRelease(dict); + } else NSLog(@"No settings found"); + } + // Enable GUI components + [self inputEnable:YES]; + // Set LED and manual motor control +// [self updateLED:0x0a]; +// [self setMotorOverride:TRUE]; +// [self testMotorsLarge:0 small:0]; + largeMotor=0; + smallMotor=0; + // Battery level? + { + NSBundle *bundle = [NSBundle bundleForClass:[self class]]; + NSString *path; + CFTypeRef prop; + + path = nil; + if (IOObjectConformsTo(registryEntry, "WirelessHIDDevice")) + { + prop = IORegistryEntryCreateCFProperty(registryEntry, CFSTR("BatteryLevel"), NULL, 0); + if (prop != nil) + { + unsigned char level; + + if (CFNumberGetValue(prop, kCFNumberCharType, &level)) + path = [bundle pathForResource:[NSString stringWithFormat:@"batt%i", level / 64] ofType:@"tif"]; + CFRelease(prop); + } + [powerOff setHidden:NO]; + } + if (path == nil) + path = [bundle pathForResource:@"battNone" ofType:@"tif"]; + [batteryLevel setImage:[[[NSImage alloc] initByReferencingFile:path] autorelease]]; + } +} + +// Clear out the device lists +- (void)deleteDeviceList +{ + [deviceList removeAllItems]; + [deviceArray removeAllObjects]; +} + +// Update the device list from the I/O Kit +- (void)updateDeviceList +{ + CFMutableDictionaryRef hidDictionary; + IOReturn ioReturn; + io_iterator_t iterator; + io_object_t hidDevice, parent; + int count; + DeviceItem *item; + + // Scrub old items + [self stopDevice]; + [self deleteDeviceList]; + // Add new items + hidDictionary=IOServiceMatching(kIOHIDDeviceKey); + ioReturn=IOServiceGetMatchingServices(masterPort,hidDictionary,&iterator); + if((ioReturn!=kIOReturnSuccess)||(iterator==0)) { + [deviceList addItemWithTitle:NO_ITEMS]; + return; + } + count=0; + while((hidDevice=IOIteratorNext(iterator))) { + parent = 0; + IORegistryEntryGetParentEntry(hidDevice, kIOServicePlane, &parent); + BOOL deviceWired = IOObjectConformsTo(parent, "Xbox360Peripheral") && IOObjectConformsTo(hidDevice, "Xbox360ControllerClass"); + BOOL deviceWireless = IOObjectConformsTo(hidDevice, "WirelessHIDDevice"); + if ((!deviceWired) && (!deviceWireless)) + { + IOObjectRelease(hidDevice); + continue; + } + item=[DeviceItem allocateDeviceItemForDevice:hidDevice]; + if(item==NULL) continue; + // Add to item + NSString *name; + name = [item name]; + if (name == nil) + name = @"Generic Controller"; + [deviceList addItemWithTitle:[NSString stringWithFormat:@"%i: %@ (%@)", ++count, name, deviceWireless ? @"Wireless" : @"Wired"]]; + [deviceArray addObject:item]; + } + IOObjectRelease(iterator); + if(count==0) [deviceList addItemWithTitle:NO_ITEMS]; + [self startDevice]; +} + +// Start up +- (void)mainViewDidLoad +{ + io_object_t object; + + // Get master port, for accessing I/O Kit + IOMasterPort(MACH_PORT_NULL,&masterPort); + // Set up notification of USB device addition/removal + notifyPort=IONotificationPortCreate(masterPort); + notifySource=IONotificationPortGetRunLoopSource(notifyPort); + CFRunLoopAddSource(CFRunLoopGetCurrent(),notifySource,kCFRunLoopCommonModes); + // Prepare other fields + deviceArray=[[NSMutableArray arrayWithCapacity:1] retain]; + device=NULL; + hidQueue=NULL; + // Activate callbacks + // Wired + IOServiceAddMatchingNotification(notifyPort, kIOFirstMatchNotification, IOServiceMatching(kIOUSBDeviceClassName), callbackHandleDevice, self, &onIteratorWired); + callbackHandleDevice(self, onIteratorWired); + IOServiceAddMatchingNotification(notifyPort, kIOTerminatedNotification, IOServiceMatching(kIOUSBDeviceClassName), callbackHandleDevice, self, &offIteratorWired); + while((object = IOIteratorNext(offIteratorWired)) != 0) + IOObjectRelease(object); + // Wireless + IOServiceAddMatchingNotification(notifyPort, kIOFirstMatchNotification, IOServiceMatching("WirelessHIDDevice"), callbackHandleDevice, self, &onIteratorWireless); + callbackHandleDevice(self, onIteratorWireless); + IOServiceAddMatchingNotification(notifyPort, kIOTerminatedNotification, IOServiceMatching("WirelessHIDDevice"), callbackHandleDevice, self, &offIteratorWireless); + while((object = IOIteratorNext(offIteratorWireless)) != 0) + IOObjectRelease(object); +} + +// Shut down +- (void)dealloc +{ + int i; + DeviceItem *item; + FFEFFESCAPE escape; + unsigned char c; + + // Remove notification source + IOObjectRelease(onIteratorWired); + IOObjectRelease(onIteratorWireless); + IOObjectRelease(offIteratorWired); + IOObjectRelease(offIteratorWireless); + CFRunLoopRemoveSource(CFRunLoopGetCurrent(),notifySource,kCFRunLoopCommonModes); + CFRunLoopSourceInvalidate(notifySource); + IONotificationPortDestroy(notifyPort); + // Release device and info + [self stopDevice]; + for (i = 0; i < [deviceArray count]; i++) + { + item = [deviceArray objectAtIndex:i]; + if ([item ffDevice] == 0) + continue; + c = 0x06 + (i % 0x04); + escape.dwSize = sizeof(escape); + escape.dwCommand = 0x02; + escape.cbInBuffer = sizeof(c); + escape.lpvInBuffer = &c; + escape.cbOutBuffer = 0; + escape.lpvOutBuffer = NULL; + FFDeviceEscape([item ffDevice], &escape); + } + [self deleteDeviceList]; + [deviceArray release]; + // Close master port + mach_port_deallocate(mach_task_self(),masterPort); + // Done + [super dealloc]; +} + +- (mach_port_t)masterPort +{ + return masterPort; +} + +// Handle selection from drop down menu +- (void)selectDevice:(id)sender +{ + [self startDevice]; +} + +// Handle changing a setting +- (void)changeSetting:(id)sender +{ + CFDictionaryRef dict; + CFStringRef keys[8]; + CFTypeRef values[8]; + UInt16 i; + + // Set keys and values + keys[0]=CFSTR("InvertLeftX"); + values[0]=([leftStickInvertX state]==NSOnState)?kCFBooleanTrue:kCFBooleanFalse; + keys[1]=CFSTR("InvertLeftY"); + values[1]=([leftStickInvertY state]==NSOnState)?kCFBooleanTrue:kCFBooleanFalse; + keys[2]=CFSTR("InvertRightX"); + values[2]=([rightStickInvertX state]==NSOnState)?kCFBooleanTrue:kCFBooleanFalse; + keys[3]=CFSTR("InvertRightY"); + values[3]=([rightStickInvertY state]==NSOnState)?kCFBooleanTrue:kCFBooleanFalse; + keys[4]=CFSTR("DeadzoneLeft"); + i=[leftStickDeadzone doubleValue]; + values[4]=CFNumberCreate(NULL,kCFNumberShortType,&i); + keys[5]=CFSTR("DeadzoneRight"); + i=[rightStickDeadzone doubleValue]; + values[5]=CFNumberCreate(NULL,kCFNumberShortType,&i); + keys[6]=CFSTR("RelativeLeft"); + values[6]=([leftLinked state]==NSOnState)?kCFBooleanTrue:kCFBooleanFalse; + keys[7]=CFSTR("RelativeRight"); + values[7]=([rightLinked state]==NSOnState)?kCFBooleanTrue:kCFBooleanFalse; + // Create dictionary + dict=CFDictionaryCreate(NULL,(const void**)keys,(const void**)values,sizeof(keys)/sizeof(keys[0]),&kCFTypeDictionaryKeyCallBacks,&kCFTypeDictionaryValueCallBacks); + // Set property + IORegistryEntrySetCFProperties(registryEntry, dict); + SetController(GetSerialNumber(registryEntry), (NSDictionary*)dict); + // Update UI + [leftStick setLinked:([leftLinked state]==NSOnState)]; + [leftStick setDeadzone:[leftStickDeadzone doubleValue]]; + [rightStick setLinked:([rightLinked state]==NSOnState)]; + [rightStick setDeadzone:[rightStickDeadzone doubleValue]]; +} + +// Handle I/O Kit device add/remove +- (void)handleDeviceChange +{ + // Ideally, this function would make a note of the controller's Location ID, then + // reselect it when the list is updated, if it's still in the list. + [self updateDeviceList]; +} + +- (IBAction)showDeviceList:(id)sender +{ + [deviceLister showWithOwner:self]; +} + +- (IBAction)powerOff:(id)sender +{ + FFEFFESCAPE escape; + + if(ffDevice==0) return; + escape.dwSize=sizeof(escape); + escape.dwCommand=0x03; + escape.cbInBuffer=0; + escape.lpvInBuffer=NULL; + escape.cbOutBuffer=0; + escape.lpvOutBuffer=NULL; + FFDeviceEscape(ffDevice,&escape); +} + +@end diff --git a/Pref360Control/Pref360Control_Prefix.pch b/Pref360Control/Pref360Control_Prefix.pch new file mode 100644 index 00000000..5da80c02 --- /dev/null +++ b/Pref360Control/Pref360Control_Prefix.pch @@ -0,0 +1,8 @@ +// +// Prefix header for all source files of the 'Pref360Control' target in the 'Pref360Control' project. +// + +#ifdef __OBJC__ + #import + #import +#endif diff --git a/Pref360Control/batt0.tif b/Pref360Control/batt0.tif new file mode 100644 index 00000000..ff3b09c3 Binary files /dev/null and b/Pref360Control/batt0.tif differ diff --git a/Pref360Control/batt1.tif b/Pref360Control/batt1.tif new file mode 100644 index 00000000..42b52186 Binary files /dev/null and b/Pref360Control/batt1.tif differ diff --git a/Pref360Control/batt2.tif b/Pref360Control/batt2.tif new file mode 100644 index 00000000..5475dc41 Binary files /dev/null and b/Pref360Control/batt2.tif differ diff --git a/Pref360Control/batt3.tif b/Pref360Control/batt3.tif new file mode 100644 index 00000000..f0424a7f Binary files /dev/null and b/Pref360Control/batt3.tif differ diff --git a/Pref360Control/battNone.tif b/Pref360Control/battNone.tif new file mode 100644 index 00000000..6f1aa628 Binary files /dev/null and b/Pref360Control/battNone.tif differ diff --git a/Pref360Control/pref360controlpref.tiff b/Pref360Control/pref360controlpref.tiff new file mode 100644 index 00000000..d8d477b6 Binary files /dev/null and b/Pref360Control/pref360controlpref.tiff differ diff --git a/Pref360Control/version.plist b/Pref360Control/version.plist new file mode 100644 index 00000000..3c5239fc --- /dev/null +++ b/Pref360Control/version.plist @@ -0,0 +1,18 @@ + + + + + BuildVersion + 328 + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1.0 + ProductBuildVersion + 7K571 + ProjectName + PreferencePaneTemplate + SourceVersion + 120000 + + diff --git a/Readme.rtf b/Readme.rtf new file mode 100644 index 00000000..d59c4a4b --- /dev/null +++ b/Readme.rtf @@ -0,0 +1,86 @@ +{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf340 +\cocoascreenfonts1{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +{\*\listtable{\list\listtemplateid1\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid1\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid1} +{\list\listtemplateid2\listhybrid{\listlevel\levelnfc23\levelnfcn23\leveljc0\leveljcn0\levelfollow0\levelstartat1\levelspace360\levelindent0{\*\levelmarker \{disc\}}{\leveltext\leveltemplateid101\'01\uc0\u8226 ;}{\levelnumbers;}\fi-360\li720\lin720 }{\listname ;}\listid2}} +{\*\listoverridetable{\listoverride\listid1\listoverridecount0\ls1}{\listoverride\listid2\listoverridecount0\ls2}} +\paperw12240\paperh15840\margl1440\margr1440\vieww9000\viewh8400\viewkind0 +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural + +\f0\b\fs36 \cf0 XBox 360 Controller driver for Mac OS X +\b0\fs24 \ +Copyright (C) 2006-2013 Colin Munro\ +{\field{\*\fldinst{HYPERLINK "http://tattiebogle.net/index.php/ProjectRoot/Xbox360Controller"}}{\fldrslt http://tattiebogle.net/index.php/ProjectRoot/Xbox360Controller}}\ +\ + +\b About +\b0 \ +This driver supports the Microsoft Xbox 360 controller, including access to rumble motors and LEDs, on the Mac OS X platform. It includes a plugin for the Apple Force Feedback Framework so some games will be able to activate them, along with a Preference Pane with which allows you to test everything is installed correctly. Both wired 360 controllers connected via USB, and wireless 360 controllers connected via the Wireless Gaming Receiver for Windows, are supported.\ +\ + +\b Licence +\b0 \ +This driver is licensed under the GNU Public License. A copy of this license is included in the distribution file, please inspect it before using the binary or source.\ +\ + +\b Installation +\b0 \ +Simply complete the installer package to install the driver. The driver will recommend you restart - if you do not, the driver will only be usable if the controller is already connected or connected within a minute after the installer completes. If you are interested in installing as a developer please see below.\ +\ + +\b Usage +\b0 \ +The driver exposes a standard game pad with a number of standard controls, so any game that supports gaming devices should work. In some cases this may need an update from the manufacturer of the game or a patched version. The Preference Pane uses the standard Mac OS X Frameworks for accessing HID devices and accessing Force Feedback capabilities, so should be a good test that the installation is functional.\ +\ + +\b Known Problems/Todo +\b0 \ +\pard\tx220\tx720\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li720\fi-720\pardirnatural +\ls1\ilvl0\cf0 {\listtext \'95 }The rumble motor test on the triggers of the Preference Pane bypasses the Force Feedback Framework functionality, so isn't actually testing it. It really should, for completeness (and it'd help adding support for more complex effects) - this test is now disabled in the normal release anyway\ +{\listtext \'95 }Force Feedback plugin may make effects run slower (e.g. longer time) than they should\ +{\listtext \'95 }Driver probably needs to be more resilient to errors and odd cases\ +{\listtext \'95 }Better Force Feedback "emulation"\ +{\listtext \'95 }Extra settings? E.g. trigger deadzones, control remapping.\ +{\listtext \'95 }Someone has requested old Xbox Controller support too.\ +\pard\tx220\tx720\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\li720\fi-720\pardirnatural +\ls2\ilvl0 +\b \cf0 \ +Contact me +\b0 \ +\pard\tx0\tx220\tx660\tx720\tx740\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural +\ls2\ilvl0\cf0 Please feel free to contact me with any comments, questions and so on using the form at the URL at the top of the file.\ +\ +\pard\tx0\tx220\tx660\tx720\tx740\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural +\ls2\ilvl0 +\b \cf0 Developer info +\b0 \ +Anything below this probably doesn't affect end users, so you can stop reading now if you just want to use the driver.\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural +\cf0 \ + +\b Building +\b0 \ +(This section does not yet discuss the source of the wireless drivers)\ +The distribution currently consists of 3 projects - one for the driver (implemented in C++, as an I/O Kit C++ class), one for the force feedback support plugin (implemented in C, as an I/O Kit COM plugin) and one for the Preference Pane (implemented in Objective C as a preference pane plugin). Ideally these 3 targets should be in the same project, but I've not worked on this yet.\ +\ +To build, use the standard Xcode build for Deployment on each of the 3 projects. Build Feedback360 before 360Controller, as the 360Controller project includes a script to copy the Feedback360 bundle to the correct place in the .kext to make it work.\ +\ +To debug the driver, sudo cp -R 360Controller.kext /tmp/ to assign the correct properties - note that the Force Feedback plugin only seems to be found by OSX if the driver is in /System/Library/Extensions so I could only debug it in place.\ +\ +To test the Preference Pane, just double-click the resulting file.\ +\ + +\b Debugging +\b0 \ +Most of the debugging I did was via printing out text. In 360Controller, you can use IOLog(), and the output will appear in system.log. In Feedback360 normal fprintf(stderr,...), and the output will appear on the console of whatever application is attempting to use Force Feedback. In Pref360Control NSLog() works as it's an Objective C program, and will output to the console of the Preferences application.\ +\ + +\b Installer +\b0 \ +Included is an installer project for Iceberg. Download Iceberg at {\field{\*\fldinst{HYPERLINK "http://s.sudre.free.fr/Software/Iceberg.html"}}{\fldrslt http://s.sudre.free.fr/Software/Iceberg.html}}\ +\ + +\b Other information +\b0 \ +I wrote the driver from scratch, using Apple documentation and drivers simply as a reference and not basing it upon any existing source. As such, some things may be done strangely or incorrectly, so excuse any weirdness. I've also tried to include comments to explain generally what's going on :)\ +} \ No newline at end of file diff --git a/Wireless360Controller/English.lproj/InfoPlist.strings b/Wireless360Controller/English.lproj/InfoPlist.strings new file mode 100644 index 00000000..21684541 Binary files /dev/null and b/Wireless360Controller/English.lproj/InfoPlist.strings differ diff --git a/Wireless360Controller/IOKitDriver.pbproj/project.pbxproj b/Wireless360Controller/IOKitDriver.pbproj/project.pbxproj new file mode 100644 index 00000000..d24a1a05 --- /dev/null +++ b/Wireless360Controller/IOKitDriver.pbproj/project.pbxproj @@ -0,0 +1,311 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 39; + objects = { + 06AA1265FFB2107B11CA28AA = { + buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + OPTIMIZATION_CFLAGS = "-O0"; + ZERO_LINK = YES; + }; + isa = PBXBuildStyle; + name = Development; + }; + 06AA1266FFB2107B11CA28AA = { + buildSettings = { + COPY_PHASE_STRIP = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + ZERO_LINK = NO; + }; + isa = PBXBuildStyle; + name = Deployment; + }; +//060 +//061 +//062 +//063 +//064 +//080 +//081 +//082 +//083 +//084 + 089C1669FE841209C02AAC07 = { + buildSettings = { + }; + buildStyles = ( + 06AA1265FFB2107B11CA28AA, + 06AA1266FFB2107B11CA28AA, + ); + hasScannedForEncodings = 1; + isa = PBXProject; + mainGroup = 089C166AFE841209C02AAC07; + projectDirPath = ""; + targets = ( + 32D94FC30562CBF700B6AF17, + ); + }; + 089C166AFE841209C02AAC07 = { + children = ( + 247142CAFF3F8F9811CA285C, + 8DA80CCF06AD972A00E5AC22, + 089C167CFE841241C02AAC07, + 19C28FB6FE9D52B211CA2CBB, + ); + isa = PBXGroup; + name = "«PROJECTNAME»"; + refType = 4; + sourceTree = ""; + }; + 089C167CFE841241C02AAC07 = { + children = ( + 32D94FCF0562CBF700B6AF17, + 089C167DFE841241C02AAC07, + ); + isa = PBXGroup; + name = Resources; + refType = 4; + sourceTree = ""; + }; + 089C167DFE841241C02AAC07 = { + children = ( + 089C167EFE841241C02AAC07, + ); + isa = PBXVariantGroup; + name = InfoPlist.strings; + refType = 4; + sourceTree = ""; + }; + 089C167EFE841241C02AAC07 = { + fileEncoding = 10; + isa = PBXFileReference; + lastKnownFileType = text.plist.strings; + name = English; + path = English.lproj/InfoPlist.strings; + refType = 4; + sourceTree = ""; + }; +//080 +//081 +//082 +//083 +//084 +//190 +//191 +//192 +//193 +//194 + 19C28FB6FE9D52B211CA2CBB = { + children = ( + 32D94FD00562CBF700B6AF17, + ); + isa = PBXGroup; + name = Products; + refType = 4; + sourceTree = ""; + }; +//190 +//191 +//192 +//193 +//194 +//1A0 +//1A1 +//1A2 +//1A3 +//1A4 + 1A224C3EFF42367911CA2CB7 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = file; + path = "«PROJECTNAMEASIDENTIFIER».h"; + refType = 4; + sourceTree = ""; + }; + 1A224C3FFF42367911CA2CB7 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = file; + path = "«PROJECTNAMEASIDENTIFIER».cpp"; + refType = 4; + sourceTree = ""; + }; +//1A0 +//1A1 +//1A2 +//1A3 +//1A4 +//240 +//241 +//242 +//243 +//244 + 247142CAFF3F8F9811CA285C = { + children = ( + 1A224C3EFF42367911CA2CB7, + 1A224C3FFF42367911CA2CB7, + ); + isa = PBXGroup; + name = Source; + path = ""; + refType = 4; + sourceTree = ""; + }; +//240 +//241 +//242 +//243 +//244 +//320 +//321 +//322 +//323 +//324 + 32D94FC30562CBF700B6AF17 = { + buildPhases = ( + 32D94FC40562CBF700B6AF17, + 32D94FC50562CBF700B6AF17, + 32D94FC70562CBF700B6AF17, + 32D94FC90562CBF700B6AF17, + 32D94FCB0562CBF700B6AF17, + 32D94FCC0562CBF700B6AF17, + 32D94FCD0562CBF700B6AF17, + ); + buildRules = ( + ); + buildSettings = { + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Extensions"; + MODULE_NAME = "com.yourcompany.driver.«PROJECTNAMEASIDENTIFIER»"; + MODULE_VERSION = 1.0.0d1; + PRODUCT_NAME = "«PROJECTNAME»"; + WRAPPER_EXTENSION = kext; + }; + dependencies = ( + ); + isa = PBXNativeTarget; + name = "«PROJECTNAME»"; + productInstallPath = "$(SYSTEM_LIBRARY_DIR)/Extensions"; + productName = "«PROJECTNAME»"; + productReference = 32D94FD00562CBF700B6AF17; + productType = "com.apple.product-type.kernel-extension.iokit"; + }; + 32D94FC40562CBF700B6AF17 = { + buildActionMask = 2147483647; + files = ( + ); + isa = PBXShellScriptBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "script=\"${SYSTEM_DEVELOPER_DIR}/ProjectBuilder Extras/Kernel Extension Support/KEXTPreprocess\";\nif [ -x \"$script\" ]; then\n . \"$script\"\nfi"; + }; + 32D94FC50562CBF700B6AF17 = { + buildActionMask = 2147483647; + files = ( + 32D94FC60562CBF700B6AF17, + ); + isa = PBXHeadersBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + 32D94FC60562CBF700B6AF17 = { + fileRef = 1A224C3EFF42367911CA2CB7; + isa = PBXBuildFile; + settings = { + }; + }; + 32D94FC70562CBF700B6AF17 = { + buildActionMask = 2147483647; + files = ( + 32D94FC80562CBF700B6AF17, + ); + isa = PBXResourcesBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + 32D94FC80562CBF700B6AF17 = { + fileRef = 089C167DFE841241C02AAC07; + isa = PBXBuildFile; + settings = { + }; + }; + 32D94FC90562CBF700B6AF17 = { + buildActionMask = 2147483647; + files = ( + 32D94FCA0562CBF700B6AF17, + ); + isa = PBXSourcesBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + 32D94FCA0562CBF700B6AF17 = { + fileRef = 1A224C3FFF42367911CA2CB7; + isa = PBXBuildFile; + settings = { + ATTRIBUTES = ( + ); + }; + }; + 32D94FCB0562CBF700B6AF17 = { + buildActionMask = 2147483647; + files = ( + ); + isa = PBXFrameworksBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + 32D94FCC0562CBF700B6AF17 = { + buildActionMask = 2147483647; + files = ( + ); + isa = PBXRezBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + 32D94FCD0562CBF700B6AF17 = { + buildActionMask = 2147483647; + files = ( + ); + isa = PBXShellScriptBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "script=\"${SYSTEM_DEVELOPER_DIR}/ProjectBuilder Extras/Kernel Extension Support/KEXTPostprocess\";\nif [ -x \"$script\" ]; then\n . \"$script\"\nfi"; + }; + 32D94FCF0562CBF700B6AF17 = { + isa = PBXFileReference; + lastKnownFileType = text.xml; + path = Info.plist; + refType = 4; + sourceTree = ""; + }; + 32D94FD00562CBF700B6AF17 = { + explicitFileType = wrapper.cfbundle; + includeInIndex = 0; + isa = PBXFileReference; + path = "«PROJECTNAME».kext"; + refType = 3; + sourceTree = BUILT_PRODUCTS_DIR; + }; +//320 +//321 +//322 +//323 +//324 +//8D0 +//8D1 +//8D2 +//8D3 +//8D4 + 8DA80CCF06AD972A00E5AC22 = { + isa = PBXFileReference; + lastKnownFileType = wrapper.framework; + name = Kernel.framework; + path = /System/Library/Frameworks/Kernel.framework; + refType = 0; + sourceTree = ""; + }; + }; + rootObject = 089C1669FE841209C02AAC07; +} diff --git a/Wireless360Controller/Info.plist b/Wireless360Controller/Info.plist new file mode 100644 index 00000000..1164471b --- /dev/null +++ b/Wireless360Controller/Info.plist @@ -0,0 +1,58 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + com.mice.driver.Wireless360Controller + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + KEXT + CFBundleSignature + ???? + CFBundleVersion + 1.0.0d12 + IOKitPersonalities + + Wireless360Controller + + CFBundleIdentifier + com.mice.driver.Wireless360Controller + IOCFPlugInTypes + + F4545CE5-BF5B-11D6-A4BB-0003933E3E3E + 360Controller.kext/Contents/PlugIns/Feedback360.plugin + + IOClass + Wireless360Controller + IOKitDebug + 65536 + IOProviderClass + WirelessDevice + Wireless360Device + 0 + + + OSBundleLibraries + + com.apple.iokit.IOHIDFamily + 1.2 + com.apple.kpi.iokit + 8.0.0 + com.apple.kpi.libkern + 8.0.0 + com.apple.kpi.mach + 8.0.0 + com.mice.driver.WirelessGamingReceiver + 1.0.0d1 + + + diff --git a/Wireless360Controller/Wireless360Controller.cpp b/Wireless360Controller/Wireless360Controller.cpp new file mode 100644 index 00000000..88d06712 --- /dev/null +++ b/Wireless360Controller/Wireless360Controller.cpp @@ -0,0 +1,248 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + Wireless360Controller.cpp - main source of the standard wireless controller driver + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include +#include "Wireless360Controller.h" +#include "../WirelessGamingReceiver/WirelessDevice.h" +#include "../360Controller/ControlStruct.h" +#include "../360Controller/xbox360hid.h" + +#define kDriverSettingKey "DeviceData" + +OSDefineMetaClassAndStructors(Wireless360Controller, WirelessHIDDevice) +#define super WirelessHIDDevice + +static inline XBox360_SShort getAbsolute(XBox360_SShort value) +{ + XBox360_SShort reverse; + +#ifdef __LITTLE_ENDIAN__ + reverse=value; +#elif __BIG_ENDIAN__ + reverse=((value&0xFF00)>>8)|((value&0x00FF)<<8); +#else +#error Unknown CPU byte order +#endif + return (reverse<0)?~reverse:reverse; +} + +bool Wireless360Controller::init(OSDictionary *propTable) +{ + bool res = super::init(propTable); + + // Default settings + invertLeftX=invertLeftY=FALSE; + invertRightX=invertRightY=FALSE; + deadzoneLeft=deadzoneRight=0; + relativeLeft=relativeRight=FALSE; + readSettings(); + + // Done + return res; +} + +// Read the settings from the registry +void Wireless360Controller::readSettings(void) +{ + OSDictionary *dataDictionary; + OSBoolean *value; + OSNumber *number; + + dataDictionary=OSDynamicCast(OSDictionary,getProperty(kDriverSettingKey)); + if(dataDictionary==NULL) return; + value=OSDynamicCast(OSBoolean,dataDictionary->getObject("InvertLeftX")); + if(value!=NULL) invertLeftX=value->getValue(); + value=OSDynamicCast(OSBoolean,dataDictionary->getObject("InvertLeftY")); + if(value!=NULL) invertLeftY=value->getValue(); + value=OSDynamicCast(OSBoolean,dataDictionary->getObject("InvertRightX")); + if(value!=NULL) invertRightX=value->getValue(); + value=OSDynamicCast(OSBoolean,dataDictionary->getObject("InvertRightY")); + if(value!=NULL) invertRightY=value->getValue(); + number=OSDynamicCast(OSNumber,dataDictionary->getObject("DeadzoneLeft")); + if(number!=NULL) deadzoneLeft=number->unsigned32BitValue(); + number=OSDynamicCast(OSNumber,dataDictionary->getObject("DeadzoneRight")); + if(number!=NULL) deadzoneRight=number->unsigned32BitValue(); + value=OSDynamicCast(OSBoolean,dataDictionary->getObject("RelativeLeft")); + if(value!=NULL) relativeLeft=value->getValue(); + value=OSDynamicCast(OSBoolean,dataDictionary->getObject("RelativeRight")); + if(value!=NULL) relativeRight=value->getValue(); + /* + IOLog("Xbox360ControllerClass preferences loaded:\n invertLeft X: %s, Y: %s\n invertRight X: %s, Y:%s\n deadzone Left: %d, Right: %d\n\n", + invertLeftX?"True":"False",invertLeftY?"True":"False", + invertRightX?"True":"False",invertRightY?"True":"False", + deadzoneLeft,deadzoneRight); + */ +} + +// Adjusts the report for any settings specified by the user +void Wireless360Controller::fiddleReport(unsigned char *data, int length) +{ + XBOX360_IN_REPORT *report = (XBOX360_IN_REPORT*)data; + + if (invertLeftX) + report->left.x = ~report->left.x; + if (!invertLeftY) + report->left.y = ~report->left.y; + if (invertRightX) + report->right.x = ~report->right.x; + if (!invertRightY) + report->right.y = ~report->right.y; + + if (deadzoneLeft != 0) + { + if (relativeLeft) + { + if ((getAbsolute(report->left.x) < deadzoneLeft) && (getAbsolute(report->left.y) < deadzoneLeft)) + { + report->left.x = 0; + report->left.y = 0; + } + } + else + { + if (getAbsolute(report->left.x) < deadzoneLeft) + report->left.x = 0; + if (getAbsolute(report->left.y) < deadzoneLeft) + report->left.y = 0; + } + } + if (deadzoneRight != 0) + { + if (relativeRight) + { + if ((getAbsolute(report->right.x) < deadzoneRight) && (getAbsolute(report->right.y) < deadzoneRight)) + { + report->right.x = 0; + report->right.y = 0; + } + } + else + { + if (getAbsolute(report->right.x) < deadzoneRight) + report->right.x = 0; + if (getAbsolute(report->right.y) < deadzoneRight) + report->right.y = 0; + } + } +} + +void Wireless360Controller::receivedHIDupdate(unsigned char *data, int length) +{ + fiddleReport(data, length); + super::receivedHIDupdate(data, length); +} + +void Wireless360Controller::SetRumbleMotors(unsigned char large, unsigned char small) +{ + char buf[] = {0x00, 0x01, 0x0f, 0xc0, 0x00, large, small, 0x00, 0x00, 0x00, 0x00, 0x00}; + WirelessDevice *device; + + device = OSDynamicCast(WirelessDevice, getProvider()); + if (device != NULL) + device->SendPacket(buf, sizeof(buf)); +} + +IOReturn Wireless360Controller::setReport(IOMemoryDescriptor *report, IOHIDReportType reportType, IOOptionBits options) +{ + char data[2]; + +// IOLog("setReport(%p, %d, %d)\n", report, reportType, options); + if (report->readBytes(0, data, 2) < 2) + return kIOReturnUnsupported; + + // Rumble + if (data[0] == 0x00) + { + if ((data[1] != report->getLength()) || (data[1] != 0x04)) + return kIOReturnUnsupported; + report->readBytes(2, data, 2); + SetRumbleMotors(data[0], data[1]); + return kIOReturnSuccess; + } + + return super::setReport(report, reportType, options); +} + +IOReturn Wireless360Controller::newReportDescriptor(IOMemoryDescriptor ** descriptor ) const +{ + IOBufferMemoryDescriptor *buffer; + + buffer = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, 0, sizeof(ReportDescriptor)); + if (buffer == NULL) + return kIOReturnNoResources; + buffer->writeBytes(0, ReportDescriptor, sizeof(ReportDescriptor)); + *descriptor = buffer; + return kIOReturnSuccess; +} + +// Called by the userspace IORegistryEntrySetCFProperties function +IOReturn Wireless360Controller::setProperties(OSObject *properties) +{ + OSDictionary *dictionary; + + dictionary=OSDynamicCast(OSDictionary,properties); + if(dictionary!=NULL) { + setProperty(kDriverSettingKey,dictionary); + readSettings(); + return kIOReturnSuccess; + } else return kIOReturnBadArgument; +} + +// Get info + +OSString* Wireless360Controller::newManufacturerString() const +{ + return OSString::withCString("Microsoft"); +} + +OSNumber* Wireless360Controller::newPrimaryUsageNumber() const +{ + // Gamepad + return OSNumber::withNumber(0x05, 8); +} + +OSNumber* Wireless360Controller::newPrimaryUsagePageNumber() const +{ + // Generic Desktop + return OSNumber::withNumber(0x01, 8); +} + +OSNumber* Wireless360Controller::newProductIDNumber() const +{ + return OSNumber::withNumber((unsigned long long)0x28e, 16); +} + +OSString* Wireless360Controller::newProductString() const +{ + return OSString::withCString("Wireless 360 Controller"); +} + +OSString* Wireless360Controller::newTransportString() const +{ + return OSString::withCString("Wireless"); +} + +OSNumber* Wireless360Controller::newVendorIDNumber() const +{ + return OSNumber::withNumber((unsigned long long)0x45e, 16); +} + diff --git a/Wireless360Controller/Wireless360Controller.h b/Wireless360Controller/Wireless360Controller.h new file mode 100644 index 00000000..cd2616d7 --- /dev/null +++ b/Wireless360Controller/Wireless360Controller.h @@ -0,0 +1,61 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + Wireless360Controller.h - declaration of the wireless controller driver class + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef __WIRELESS360CONTROLLER_H__ +#define __WIRELESS360CONTROLLER_H__ + +#include "../WirelessGamingReceiver/WirelessHIDDevice.h" + +class Wireless360Controller : public WirelessHIDDevice +{ + OSDeclareDefaultStructors(Wireless360Controller); +public: + bool init(OSDictionary *propTable = NULL); + + void SetRumbleMotors(unsigned char large, unsigned char small); + + IOReturn setReport(IOMemoryDescriptor *report, IOHIDReportType reportType, IOOptionBits options); + IOReturn newReportDescriptor(IOMemoryDescriptor ** descriptor ) const; + + IOReturn setProperties(OSObject *properties); + + virtual OSString* newManufacturerString() const; + virtual OSNumber* newPrimaryUsageNumber() const; + virtual OSNumber* newPrimaryUsagePageNumber() const; + virtual OSNumber* newProductIDNumber() const; + virtual OSString* newProductString() const; + virtual OSString* newTransportString() const; + virtual OSNumber* newVendorIDNumber() const; +protected: + void readSettings(void); + void receivedHIDupdate(unsigned char *data, int length); + + // Settings + bool invertLeftX,invertLeftY; + bool invertRightX,invertRightY; + short deadzoneLeft,deadzoneRight; + bool relativeLeft,relativeRight; +private: + void fiddleReport(unsigned char *data, int length); +}; + +#endif // __WIRELESS360CONTROLLER_H__ diff --git a/Wireless360Controller/Wireless360Controller.xcodeproj/project.pbxproj b/Wireless360Controller/Wireless360Controller.xcodeproj/project.pbxproj new file mode 100644 index 00000000..4a3d9346 --- /dev/null +++ b/Wireless360Controller/Wireless360Controller.xcodeproj/project.pbxproj @@ -0,0 +1,259 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 32D94FC60562CBF700B6AF17 /* Wireless360Controller.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A224C3EFF42367911CA2CB7 /* Wireless360Controller.h */; }; + 32D94FC80562CBF700B6AF17 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C167DFE841241C02AAC07 /* InfoPlist.strings */; }; + 32D94FCA0562CBF700B6AF17 /* Wireless360Controller.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A224C3FFF42367911CA2CB7 /* Wireless360Controller.cpp */; settings = {ATTRIBUTES = (); }; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 089C167EFE841241C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + 1A224C3EFF42367911CA2CB7 /* Wireless360Controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Wireless360Controller.h; sourceTree = ""; }; + 1A224C3FFF42367911CA2CB7 /* Wireless360Controller.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Wireless360Controller.cpp; sourceTree = ""; }; + 32D94FCF0562CBF700B6AF17 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 32D94FD00562CBF700B6AF17 /* Wireless360Controller.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Wireless360Controller.kext; sourceTree = BUILT_PRODUCTS_DIR; }; + 8DA8362C06AD9B9200E5AC22 /* Kernel.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Kernel.framework; path = /System/Library/Frameworks/Kernel.framework; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 32D94FCB0562CBF700B6AF17 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 089C166AFE841209C02AAC07 /* Wireless360Controller */ = { + isa = PBXGroup; + children = ( + 247142CAFF3F8F9811CA285C /* Source */, + 8DA8362C06AD9B9200E5AC22 /* Kernel.framework */, + 089C167CFE841241C02AAC07 /* Resources */, + 19C28FB6FE9D52B211CA2CBB /* Products */, + ); + name = Wireless360Controller; + sourceTree = ""; + }; + 089C167CFE841241C02AAC07 /* Resources */ = { + isa = PBXGroup; + children = ( + 32D94FCF0562CBF700B6AF17 /* Info.plist */, + 089C167DFE841241C02AAC07 /* InfoPlist.strings */, + ); + name = Resources; + sourceTree = ""; + }; + 19C28FB6FE9D52B211CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 32D94FD00562CBF700B6AF17 /* Wireless360Controller.kext */, + ); + name = Products; + sourceTree = ""; + }; + 247142CAFF3F8F9811CA285C /* Source */ = { + isa = PBXGroup; + children = ( + 1A224C3EFF42367911CA2CB7 /* Wireless360Controller.h */, + 1A224C3FFF42367911CA2CB7 /* Wireless360Controller.cpp */, + ); + name = Source; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 32D94FC50562CBF700B6AF17 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 32D94FC60562CBF700B6AF17 /* Wireless360Controller.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 32D94FC30562CBF700B6AF17 /* Wireless360Controller */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB91D908733DB10010E9CD /* Build configuration list for PBXNativeTarget "Wireless360Controller" */; + buildPhases = ( + 32D94FC50562CBF700B6AF17 /* Headers */, + 32D94FC70562CBF700B6AF17 /* Resources */, + 32D94FC90562CBF700B6AF17 /* Sources */, + 32D94FCB0562CBF700B6AF17 /* Frameworks */, + 32D94FCC0562CBF700B6AF17 /* Rez */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Wireless360Controller; + productInstallPath = "$(SYSTEM_LIBRARY_DIR)/Extensions"; + productName = Wireless360Controller; + productReference = 32D94FD00562CBF700B6AF17 /* Wireless360Controller.kext */; + productType = "com.apple.product-type.kernel-extension.iokit"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 089C1669FE841209C02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB91DD08733DB10010E9CD /* Build configuration list for PBXProject "Wireless360Controller" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 089C166AFE841209C02AAC07 /* Wireless360Controller */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 32D94FC30562CBF700B6AF17 /* Wireless360Controller */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 32D94FC70562CBF700B6AF17 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 32D94FC80562CBF700B6AF17 /* InfoPlist.strings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXRezBuildPhase section */ + 32D94FCC0562CBF700B6AF17 /* Rez */ = { + isa = PBXRezBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXRezBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 32D94FC90562CBF700B6AF17 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 32D94FCA0562CBF700B6AF17 /* Wireless360Controller.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 089C167DFE841241C02AAC07 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 089C167EFE841241C02AAC07 /* English */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 1DEB91DA08733DB10010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1.0.0d12; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Extensions"; + MODULE_NAME = com.mice.driver.Wireless360Controller; + MODULE_VERSION = 1.0.0d11; + PRODUCT_NAME = Wireless360Controller; + WRAPPER_EXTENSION = kext; + ZERO_LINK = YES; + }; + name = Debug; + }; + 1DEB91DB08733DB10010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CURRENT_PROJECT_VERSION = 1.0.0d12; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_MODEL_TUNING = G5; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Extensions"; + MODULE_NAME = com.mice.driver.Wireless360Controller; + MODULE_VERSION = 1.0.0d11; + PRODUCT_NAME = Wireless360Controller; + WRAPPER_EXTENSION = kext; + }; + name = Release; + }; + 1DEB91DE08733DB10010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "Developer ID Application: Colin Munro"; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.5; + PREBINDING = NO; + PROVISIONING_PROFILE = ""; + SDKROOT = ""; + }; + name = Debug; + }; + 1DEB91DF08733DB10010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + CODE_SIGN_IDENTITY = "Developer ID Application: Colin Munro"; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.5; + PREBINDING = NO; + PROVISIONING_PROFILE = ""; + SDKROOT = ""; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB91D908733DB10010E9CD /* Build configuration list for PBXNativeTarget "Wireless360Controller" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB91DA08733DB10010E9CD /* Debug */, + 1DEB91DB08733DB10010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB91DD08733DB10010E9CD /* Build configuration list for PBXProject "Wireless360Controller" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB91DE08733DB10010E9CD /* Debug */, + 1DEB91DF08733DB10010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 089C1669FE841209C02AAC07 /* Project object */; +} diff --git a/Wireless360Controller/version.plist b/Wireless360Controller/version.plist new file mode 100644 index 00000000..53bf3a3f --- /dev/null +++ b/Wireless360Controller/version.plist @@ -0,0 +1,16 @@ + + + + + BuildVersion + 12 + CFBundleVersion + 1.0 + ProductBuildVersion + 7K571 + ProjectName + DevToolsWizardTemplates + SourceVersion + 3870000 + + diff --git a/WirelessGamingReceiver/English.lproj/InfoPlist.strings b/WirelessGamingReceiver/English.lproj/InfoPlist.strings new file mode 100644 index 00000000..f180ed5a --- /dev/null +++ b/WirelessGamingReceiver/English.lproj/InfoPlist.strings @@ -0,0 +1,3 @@ +/* Localized versions of Info.plist keys */ + +NSHumanReadableCopyright = "© Colin Munro, 2007-11"; \ No newline at end of file diff --git a/WirelessGamingReceiver/IOKitDriver.pbproj/project.pbxproj b/WirelessGamingReceiver/IOKitDriver.pbproj/project.pbxproj new file mode 100644 index 00000000..d24a1a05 --- /dev/null +++ b/WirelessGamingReceiver/IOKitDriver.pbproj/project.pbxproj @@ -0,0 +1,311 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 39; + objects = { + 06AA1265FFB2107B11CA28AA = { + buildSettings = { + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + OPTIMIZATION_CFLAGS = "-O0"; + ZERO_LINK = YES; + }; + isa = PBXBuildStyle; + name = Development; + }; + 06AA1266FFB2107B11CA28AA = { + buildSettings = { + COPY_PHASE_STRIP = YES; + GCC_ENABLE_FIX_AND_CONTINUE = NO; + ZERO_LINK = NO; + }; + isa = PBXBuildStyle; + name = Deployment; + }; +//060 +//061 +//062 +//063 +//064 +//080 +//081 +//082 +//083 +//084 + 089C1669FE841209C02AAC07 = { + buildSettings = { + }; + buildStyles = ( + 06AA1265FFB2107B11CA28AA, + 06AA1266FFB2107B11CA28AA, + ); + hasScannedForEncodings = 1; + isa = PBXProject; + mainGroup = 089C166AFE841209C02AAC07; + projectDirPath = ""; + targets = ( + 32D94FC30562CBF700B6AF17, + ); + }; + 089C166AFE841209C02AAC07 = { + children = ( + 247142CAFF3F8F9811CA285C, + 8DA80CCF06AD972A00E5AC22, + 089C167CFE841241C02AAC07, + 19C28FB6FE9D52B211CA2CBB, + ); + isa = PBXGroup; + name = "«PROJECTNAME»"; + refType = 4; + sourceTree = ""; + }; + 089C167CFE841241C02AAC07 = { + children = ( + 32D94FCF0562CBF700B6AF17, + 089C167DFE841241C02AAC07, + ); + isa = PBXGroup; + name = Resources; + refType = 4; + sourceTree = ""; + }; + 089C167DFE841241C02AAC07 = { + children = ( + 089C167EFE841241C02AAC07, + ); + isa = PBXVariantGroup; + name = InfoPlist.strings; + refType = 4; + sourceTree = ""; + }; + 089C167EFE841241C02AAC07 = { + fileEncoding = 10; + isa = PBXFileReference; + lastKnownFileType = text.plist.strings; + name = English; + path = English.lproj/InfoPlist.strings; + refType = 4; + sourceTree = ""; + }; +//080 +//081 +//082 +//083 +//084 +//190 +//191 +//192 +//193 +//194 + 19C28FB6FE9D52B211CA2CBB = { + children = ( + 32D94FD00562CBF700B6AF17, + ); + isa = PBXGroup; + name = Products; + refType = 4; + sourceTree = ""; + }; +//190 +//191 +//192 +//193 +//194 +//1A0 +//1A1 +//1A2 +//1A3 +//1A4 + 1A224C3EFF42367911CA2CB7 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = file; + path = "«PROJECTNAMEASIDENTIFIER».h"; + refType = 4; + sourceTree = ""; + }; + 1A224C3FFF42367911CA2CB7 = { + fileEncoding = 4; + isa = PBXFileReference; + lastKnownFileType = file; + path = "«PROJECTNAMEASIDENTIFIER».cpp"; + refType = 4; + sourceTree = ""; + }; +//1A0 +//1A1 +//1A2 +//1A3 +//1A4 +//240 +//241 +//242 +//243 +//244 + 247142CAFF3F8F9811CA285C = { + children = ( + 1A224C3EFF42367911CA2CB7, + 1A224C3FFF42367911CA2CB7, + ); + isa = PBXGroup; + name = Source; + path = ""; + refType = 4; + sourceTree = ""; + }; +//240 +//241 +//242 +//243 +//244 +//320 +//321 +//322 +//323 +//324 + 32D94FC30562CBF700B6AF17 = { + buildPhases = ( + 32D94FC40562CBF700B6AF17, + 32D94FC50562CBF700B6AF17, + 32D94FC70562CBF700B6AF17, + 32D94FC90562CBF700B6AF17, + 32D94FCB0562CBF700B6AF17, + 32D94FCC0562CBF700B6AF17, + 32D94FCD0562CBF700B6AF17, + ); + buildRules = ( + ); + buildSettings = { + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Extensions"; + MODULE_NAME = "com.yourcompany.driver.«PROJECTNAMEASIDENTIFIER»"; + MODULE_VERSION = 1.0.0d1; + PRODUCT_NAME = "«PROJECTNAME»"; + WRAPPER_EXTENSION = kext; + }; + dependencies = ( + ); + isa = PBXNativeTarget; + name = "«PROJECTNAME»"; + productInstallPath = "$(SYSTEM_LIBRARY_DIR)/Extensions"; + productName = "«PROJECTNAME»"; + productReference = 32D94FD00562CBF700B6AF17; + productType = "com.apple.product-type.kernel-extension.iokit"; + }; + 32D94FC40562CBF700B6AF17 = { + buildActionMask = 2147483647; + files = ( + ); + isa = PBXShellScriptBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "script=\"${SYSTEM_DEVELOPER_DIR}/ProjectBuilder Extras/Kernel Extension Support/KEXTPreprocess\";\nif [ -x \"$script\" ]; then\n . \"$script\"\nfi"; + }; + 32D94FC50562CBF700B6AF17 = { + buildActionMask = 2147483647; + files = ( + 32D94FC60562CBF700B6AF17, + ); + isa = PBXHeadersBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + 32D94FC60562CBF700B6AF17 = { + fileRef = 1A224C3EFF42367911CA2CB7; + isa = PBXBuildFile; + settings = { + }; + }; + 32D94FC70562CBF700B6AF17 = { + buildActionMask = 2147483647; + files = ( + 32D94FC80562CBF700B6AF17, + ); + isa = PBXResourcesBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + 32D94FC80562CBF700B6AF17 = { + fileRef = 089C167DFE841241C02AAC07; + isa = PBXBuildFile; + settings = { + }; + }; + 32D94FC90562CBF700B6AF17 = { + buildActionMask = 2147483647; + files = ( + 32D94FCA0562CBF700B6AF17, + ); + isa = PBXSourcesBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + 32D94FCA0562CBF700B6AF17 = { + fileRef = 1A224C3FFF42367911CA2CB7; + isa = PBXBuildFile; + settings = { + ATTRIBUTES = ( + ); + }; + }; + 32D94FCB0562CBF700B6AF17 = { + buildActionMask = 2147483647; + files = ( + ); + isa = PBXFrameworksBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + 32D94FCC0562CBF700B6AF17 = { + buildActionMask = 2147483647; + files = ( + ); + isa = PBXRezBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + }; + 32D94FCD0562CBF700B6AF17 = { + buildActionMask = 2147483647; + files = ( + ); + isa = PBXShellScriptBuildPhase; + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "script=\"${SYSTEM_DEVELOPER_DIR}/ProjectBuilder Extras/Kernel Extension Support/KEXTPostprocess\";\nif [ -x \"$script\" ]; then\n . \"$script\"\nfi"; + }; + 32D94FCF0562CBF700B6AF17 = { + isa = PBXFileReference; + lastKnownFileType = text.xml; + path = Info.plist; + refType = 4; + sourceTree = ""; + }; + 32D94FD00562CBF700B6AF17 = { + explicitFileType = wrapper.cfbundle; + includeInIndex = 0; + isa = PBXFileReference; + path = "«PROJECTNAME».kext"; + refType = 3; + sourceTree = BUILT_PRODUCTS_DIR; + }; +//320 +//321 +//322 +//323 +//324 +//8D0 +//8D1 +//8D2 +//8D3 +//8D4 + 8DA80CCF06AD972A00E5AC22 = { + isa = PBXFileReference; + lastKnownFileType = wrapper.framework; + name = Kernel.framework; + path = /System/Library/Frameworks/Kernel.framework; + refType = 0; + sourceTree = ""; + }; + }; + rootObject = 089C1669FE841209C02AAC07; +} diff --git a/WirelessGamingReceiver/Info.plist b/WirelessGamingReceiver/Info.plist new file mode 100644 index 00000000..819f678f --- /dev/null +++ b/WirelessGamingReceiver/Info.plist @@ -0,0 +1,72 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + com.mice.driver.WirelessGamingReceiver + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + KEXT + CFBundleSignature + ???? + CFBundleVersion + 1.0.0d12 + IOKitPersonalities + + WirelessGamingReceiverForWindows + + CFBundleIdentifier + com.mice.driver.WirelessGamingReceiver + idProduct + 1817 + idVendor + 1118 + IOClass + WirelessGamingReceiver + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + + WirelessGamingReceiverForWindowsAlternate + + CFBundleIdentifier + com.mice.driver.WirelessGamingReceiver + idProduct + 657 + idVendor + 1118 + IOClass + WirelessGamingReceiver + IOKitDebug + 65535 + IOProviderClass + IOUSBDevice + + + OSBundleCompatibleVersion + 1.0.0d1 + OSBundleLibraries + + com.apple.iokit.IOHIDFamily + 1.2 + com.apple.iokit.IOUSBFamily + 1.8 + com.apple.kpi.iokit + 8.0.0 + com.apple.kpi.libkern + 8.0.0 + com.apple.kpi.mach + 8.0.0 + + + diff --git a/WirelessGamingReceiver/WirelessDevice.cpp b/WirelessGamingReceiver/WirelessDevice.cpp new file mode 100644 index 00000000..ddad5101 --- /dev/null +++ b/WirelessGamingReceiver/WirelessDevice.cpp @@ -0,0 +1,113 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + WirelessDevice.cpp - generic Wireless 360 device driver + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "WirelessDevice.h" +#include "WirelessGamingReceiver.h" + +OSDefineMetaClassAndStructors(WirelessDevice, IOService) +#define super IOService + +// Initialise wireless device +bool WirelessDevice::init(OSDictionary *dictionary) +{ + if (!super::init(dictionary)) + return false; + index = -1; + function = NULL; + return true; +} + +// Checks if there's any data for us +bool WirelessDevice::IsDataAvailable(void) +{ + if (index == -1) + return false; + WirelessGamingReceiver *receiver = OSDynamicCast(WirelessGamingReceiver, getProvider()); + if (receiver == NULL) + return false; + return receiver->IsDataQueued(index); +} + +// Gets the next item from our buffer +IOMemoryDescriptor* WirelessDevice::NextPacket(void) +{ + if (index == -1) + return NULL; + WirelessGamingReceiver *receiver = OSDynamicCast(WirelessGamingReceiver, getProvider()); + if (receiver == NULL) + return NULL; + return receiver->ReadBuffer(index); +} + +// Sends a buffer for this controller +void WirelessDevice::SendPacket(const void *data, size_t length) +{ + if (index == -1) + return; + WirelessGamingReceiver *receiver = OSDynamicCast(WirelessGamingReceiver, getProvider()); + if (receiver == NULL) + return; + receiver->QueueWrite(index, data, (UInt32)length); +} + +// Registers a callback function +void WirelessDevice::RegisterWatcher(void *target, WirelessDeviceWatcher function, void *parameter) +{ + this->target = target; + this->parameter = parameter; + this->function = function; + if ((function != NULL) && IsDataAvailable()) + NewData(); +} + +// For internal use, sets this instances index on the wireless gaming receiver +void WirelessDevice::SetIndex(int i) +{ + index = i; +} + +// Called when new data arrives +void WirelessDevice::NewData(void) +{ + if (function != NULL) + function(target, this, parameter); +} + +// Gets the location ID for this device +OSNumber* WirelessDevice::newLocationIDNumber() const +{ + OSNumber *owner; + UInt32 location = 0; + + if (index == -1) + return NULL; + WirelessGamingReceiver *receiver = OSDynamicCast(WirelessGamingReceiver, getProvider()); + if (receiver == NULL) + return NULL; + owner = receiver->newLocationIDNumber(); + if (owner != NULL) + { + location = owner->unsigned32BitValue() + 1 + index; + owner->release(); + } + return OSNumber::withNumber(location, 32); +} diff --git a/WirelessGamingReceiver/WirelessDevice.h b/WirelessGamingReceiver/WirelessDevice.h new file mode 100644 index 00000000..83dee634 --- /dev/null +++ b/WirelessGamingReceiver/WirelessDevice.h @@ -0,0 +1,58 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + WirelessDevice.h - declaration of the base wireless 360 device driver class + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef __WIRELESSDEVICE_H__ +#define __WIRELESSDEVICE_H__ + +#include + +class WirelessDevice; + +typedef void (*WirelessDeviceWatcher)(void *target, WirelessDevice *sender, void *parameter); + +class WirelessDevice : public IOService +{ + OSDeclareDefaultStructors(WirelessDevice); +public: + bool init(OSDictionary *dictionary = 0); + + // Controller interface + bool IsDataAvailable(void); + IOMemoryDescriptor* NextPacket(void); + + void SendPacket(const void *data, size_t length); + + void RegisterWatcher(void *target, WirelessDeviceWatcher function, void *parameter); + + OSNumber* newLocationIDNumber() const; +private: + friend class WirelessGamingReceiver; + void SetIndex(int i); + void NewData(void); +private: + int index; + // callback + void *target, *parameter; + WirelessDeviceWatcher function; +}; + +#endif // __WIRELESSDEVICE_H__ diff --git a/WirelessGamingReceiver/WirelessGamingReceiver.cpp b/WirelessGamingReceiver/WirelessGamingReceiver.cpp new file mode 100644 index 00000000..188745b9 --- /dev/null +++ b/WirelessGamingReceiver/WirelessGamingReceiver.cpp @@ -0,0 +1,588 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + WirelessGamingReceiver.cpp - main source of the wireless receiver driver + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include "WirelessGamingReceiver.h" +#include "WirelessDevice.h" +#include "devices.h" + +//#define PROTOCOL_DEBUG + +OSDefineMetaClassAndStructors(WirelessGamingReceiver, IOService) + +// Holds data for asynchronous reads +typedef struct +{ + int index; + IOBufferMemoryDescriptor *buffer; +} +WGRREAD; + +// Get maximum packet size for a pipe +static UInt32 GetMaxPacketSize(IOUSBPipe *pipe) +{ + const IOUSBEndpointDescriptor *ed; + + ed=pipe->GetEndpointDescriptor(); + if(ed==NULL) return 0; + else return ed->wMaxPacketSize; +} + +// Start device +bool WirelessGamingReceiver::start(IOService *provider) +{ + const IOUSBConfigurationDescriptor *cd; + IOUSBFindInterfaceRequest interfaceRequest; + IOUSBFindEndpointRequest pipeRequest; + IOUSBInterface *interface; + int iConnection, iOther, i; + + if (!IOService::start(provider)) + { +// IOLog("start - superclass failed\n"); + return false; + } + + device = OSDynamicCast(IOUSBDevice, provider); + if (device == NULL) + { +// IOLog("start - invalid provider\n"); + goto fail; + } + + // Check for configurations + if (device->GetNumConfigurations() < 1) + { + device = NULL; +// IOLog("start - device has no configurations!\n"); + goto fail; + } + + // Set configuration + cd = device->GetFullConfigurationDescriptor(0); + if (cd == NULL) + { + device = NULL; +// IOLog("start - couldn't get configuration descriptor\n"); + goto fail; + } + + if (!device->open(this)) + { + device = NULL; +// IOLog("start - failed to open device\n"); + goto fail; + } + if (device->SetConfiguration(this, cd->bConfigurationValue, true) != kIOReturnSuccess) + { +// IOLog("start - unable to set configuration\n"); + goto fail; + } + + for (i = 0; i < WIRELESS_CONNECTIONS; i++) + { + connections[i].controller = NULL; + connections[i].controllerIn = NULL; + connections[i].controllerOut = NULL; + connections[i].other = NULL; + connections[i].otherIn = NULL; + connections[i].otherOut = NULL; + connections[i].inputArray = NULL; + connections[i].service = NULL; + connections[i].controllerStarted = false; + } + + pipeRequest.interval = 0; + pipeRequest.maxPacketSize = 0; + pipeRequest.type = kUSBInterrupt; + interfaceRequest.bInterfaceClass = kIOUSBFindInterfaceDontCare; + interfaceRequest.bInterfaceSubClass = kIOUSBFindInterfaceDontCare; + interfaceRequest.bInterfaceProtocol = kIOUSBFindInterfaceDontCare; + interfaceRequest.bAlternateSetting = 0; + interface = NULL; + iConnection = 0; + iOther = 0; + while ((interface = device->FindNextInterface(interface, &interfaceRequest)) != NULL) + { + switch(interface->GetInterfaceProtocol()) + { + case 129: // Controller + if (!interface->open(this)) + { +// IOLog("start: Failed to open control interface\n"); + goto fail; + } + connections[iConnection].controller = interface; + pipeRequest.direction = kUSBIn; + connections[iConnection].controllerIn = interface->FindNextPipe(NULL, &pipeRequest); + if (connections[iConnection].controllerIn == NULL) + { +// IOLog("start: Failed to open control input pipe\n"); + goto fail; + } + else + connections[iConnection].controllerIn->retain(); + pipeRequest.direction = kUSBOut; + connections[iConnection].controllerOut = interface->FindNextPipe(NULL, &pipeRequest); + if (connections[iConnection].controllerOut == NULL) + { +// IOLog("start: Failed to open control output pipe\n"); + goto fail; + } + else + connections[iConnection].controllerOut->retain(); + iConnection++; + break; + case 130: // It is a mystery + if (!interface->open(this)) + { +// IOLog("start: Failed to open mystery interface\n"); + goto fail; + } + connections[iOther].other = interface; + pipeRequest.direction = kUSBIn; + connections[iOther].otherIn = interface->FindNextPipe(NULL, &pipeRequest); + if (connections[iOther].otherIn == NULL) + { +// IOLog("start: Failed to open mystery input pipe\n"); + goto fail; + } + else + connections[iOther].otherIn->retain(); + pipeRequest.direction = kUSBOut; + connections[iOther].otherOut = interface->FindNextPipe(NULL, &pipeRequest); + if (connections[iOther].otherOut == NULL) + { +// IOLog("start: Failed to open mystery output pipe\n"); + goto fail; + } + else + connections[iOther].otherOut->retain(); + iOther++; + break; + default: +// IOLog("start: Ignoring interface (protocol %d)\n", interface->GetInterfaceProtocol()); + break; + } + } + + if (iConnection != iOther) + IOLog("start - interface mismatch?\n"); + connectionCount = iConnection; + + for (i = 0; i < connectionCount; i++) + { + connections[i].inputArray = OSArray::withCapacity(5); + if (connections[i].inputArray == NULL) + { +// IOLog("start: Failed to allocate packet buffer %d\n", i); + goto fail; + } + if (!QueueRead(i)) + { +// IOLog("start: Failed to start read %d\n", i); + goto fail; + } + } + +// IOLog("start: Transform and roll out (%d interfaces)\n", connectionCount); + return true; + +fail: + ReleaseAll(); + return false; +} + +// Stop the device +void WirelessGamingReceiver::stop(IOService *provider) +{ + ReleaseAll(); + IOService::stop(provider); +} + +// Handle message from provider +IOReturn WirelessGamingReceiver::message(UInt32 type,IOService *provider,void *argument) +{ +// IOLog("Message\n"); +/* + switch(type) { + case kIOMessageServiceIsTerminated: + case kIOMessageServiceIsRequestingClose: + if(device->isOpen(this)) ReleaseAll(); + return kIOReturnSuccess; + default: + */ + return IOService::message(type,provider,argument); +// } +} + +// Queue a read on a controller +bool WirelessGamingReceiver::QueueRead(int index) +{ + IOUSBCompletion complete; + IOReturn err; + WGRREAD *data; + + data = (WGRREAD*)IOMalloc(sizeof(WGRREAD)); + if (data == NULL) + return false; + data->index = index; + data->buffer = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, 0, GetMaxPacketSize(connections[index].controllerIn)); + if (data->buffer == NULL) + { + IOFree(data, sizeof(WGRREAD)); + return false; + } + + complete.target = this; + complete.action = _ReadComplete; + complete.parameter = data; + + err = connections[index].controllerIn->Read(data->buffer, 0, 0, data->buffer->getLength(), &complete); + if (err == kIOReturnSuccess) + return true; + + data->buffer->release(); + IOFree(data, sizeof(WGRREAD)); + +// IOLog("read - failed to start (0x%.8x)\n", err); + return false; +} + +// Handle a completed read on a controller +void WirelessGamingReceiver::ReadComplete(void *parameter, IOReturn status, UInt32 bufferSizeRemaining) +{ + WGRREAD *data = (WGRREAD*)parameter; + bool reread = true; + + switch (status) + { + case kIOReturnOverrun: +// IOLog("read - kIOReturnOverrun, clearing stall\n"); + connections[data->index].controllerIn->ClearStall(); + // fall through + case kIOReturnSuccess: + ProcessMessage(data->index, (unsigned char*)data->buffer->getBytesNoCopy(), (int)data->buffer->getLength() - bufferSizeRemaining); + break; + case kIOReturnNotResponding: +// IOLog("read - kIOReturnNotResponding\n"); + // fall through + default: + reread = false; + break; + } + + int newIndex = data->index; + data->buffer->release(); + IOFree(data, sizeof(WGRREAD)); + + if (reread) + QueueRead(newIndex); +} + +// Queue an asynchronous write on a controller +bool WirelessGamingReceiver::QueueWrite(int index, const void *bytes, UInt32 length) +{ + IOBufferMemoryDescriptor *outBuffer; + IOUSBCompletion complete; + IOReturn err; + + outBuffer = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, 0, length); + if (outBuffer == NULL) + { +// IOLog("send - unable to allocate buffer\n"); + return false; + } + outBuffer->writeBytes(0, bytes, length); + + complete.target = this; + complete.action = _WriteComplete; + complete.parameter = outBuffer; + + err = connections[index].controllerOut->Write(outBuffer, 0, 0, length, &complete); + if (err == kIOReturnSuccess) + return true; + else + { +// IOLog("send - failed to start (0x%.8x)\n",err); + return false; + } +} + +// Handle a completed write on a controller +void WirelessGamingReceiver::WriteComplete(void *parameter,IOReturn status,UInt32 bufferSizeRemaining) +{ + IOMemoryDescriptor *memory=(IOMemoryDescriptor*)parameter; + if(status!=kIOReturnSuccess) { + IOLog("write - Error writing: 0x%.8x\n",status); + } + memory->release(); +} + +// Release any allocated objects +void WirelessGamingReceiver::ReleaseAll(void) +{ + int i; + + for (i = 0; i < connectionCount; i++) + { + if (connections[i].service != NULL) + { + connections[i].service->terminate(kIOServiceRequired); + connections[i].service->detachAll(gIOServicePlane); + connections[i].service->release(); + connections[i].service = NULL; + } + if (connections[i].controllerIn != NULL) + { + connections[i].controllerIn->Abort(); + connections[i].controllerIn->release(); + connections[i].controllerIn = NULL; + } + if (connections[i].controllerOut != NULL) + { + connections[i].controllerOut->Abort(); + connections[i].controllerOut->release(); + connections[i].controllerOut = NULL; + } + if (connections[i].controller != NULL) + { + connections[i].controller->close(this); + connections[i].controller = NULL; + } + if (connections[i].otherIn != NULL) + { + connections[i].otherIn->Abort(); + connections[i].otherIn->release(); + connections[i].otherIn = NULL; + } + if (connections[i].otherOut != NULL) + { + connections[i].otherOut->Abort(); + connections[i].otherOut->release(); + connections[i].otherOut = NULL; + } + if (connections[i].other != NULL) + { + connections[i].other->close(this); + connections[i].other = NULL; + } + if (connections[i].inputArray != NULL) + { + connections[i].inputArray->release(); + connections[i].inputArray = NULL; + } + connections[i].controllerStarted = false; + } + if (device != NULL) + { + device->close(this); + device = NULL; + } +} + +// Static wrapper for read notifications +void WirelessGamingReceiver::_ReadComplete(void *target, void *parameter, IOReturn status, UInt32 bufferSizeRemaining) +{ + if (target != NULL) + ((WirelessGamingReceiver*)target)->ReadComplete(parameter, status, bufferSizeRemaining); +} + +// Static wrapper for write notifications +void WirelessGamingReceiver::_WriteComplete(void *target, void *parameter, IOReturn status, UInt32 bufferSizeRemaining) +{ + if (target != NULL) + ((WirelessGamingReceiver*)target)->WriteComplete(parameter, status, bufferSizeRemaining); +} + +// Processes a message for a controller +void WirelessGamingReceiver::ProcessMessage(int index, const unsigned char *data, int length) +{ +#ifdef PROTOCOL_DEBUG + char s[1024]; + int i; + + for (i = 0; i < length; i++) + { + s[(i * 2) + 0] = "0123456789ABCDEF"[(data[i] & 0xF0) >> 4]; + s[(i * 2) + 1] = "0123456789ABCDEF"[data[i] & 0x0F]; + } + s[i * 2] = '\0'; + IOLog("Got data (%d, %d bytes): %s\n", index, length, s); +#endif + // Handle device connections + if ((length == 2) && (data[0] == 0x08)) + { + if (data[1] == 0x00) + { + // Device disconnected +#ifdef PROTOCOL_DEBUG + IOLog("process: Device detached\n"); +#endif + if (connections[index].service != NULL) + { + connections[index].service->SetIndex(-1); + if (connections[index].controllerStarted) + connections[index].service->terminate(kIOServiceRequired | kIOServiceSynchronous); + connections[index].service->detach(this); + connections[index].service->release(); + connections[index].service = NULL; + connections[index].controllerStarted = false; + } + } + else + { + // Device connected +#ifdef PROTOCOL_DEBUG + IOLog("process: Attempting to add new device\n"); +#endif + if (connections[index].service == NULL) + { + bool ready; + int i, j; + IOMemoryDescriptor *data; + char c; + + ready = false; + j = connections[index].inputArray->getCount(); + for (i = 0; !ready && (i < j); i++) + { + data = OSDynamicCast(IOMemoryDescriptor, connections[index].inputArray->getObject(i)); + data->readBytes(1, &c, 1); + if (c == 0x0f) + ready = true; + } + InstantiateService(index); + if (ready) + { +#ifdef PROTOCOL_DEBUG + IOLog("Registering wireless device"); +#endif + connections[index].controllerStarted = true; + connections[index].service->registerService(); + } + } + } + return; + } + + // Add anything else to the queue + IOMemoryDescriptor *copy = IOBufferMemoryDescriptor::inTaskWithOptions(kernel_task, 0, length); + copy->writeBytes(0, data, length); + connections[index].inputArray->setObject(copy); + if (connections[index].service == NULL) + InstantiateService(index); + if (connections[index].service != NULL) + { + connections[index].service->NewData(); + if (!connections[index].controllerStarted) + { + char c; + + copy->readBytes(1, &c, 1); + if (c == 0x0f) + { +#ifdef PROTOCOL_DEBUG + IOLog("Registering wireless device"); +#endif + connections[index].controllerStarted = true; + connections[index].service->registerService(); + } + } + } + copy->release(); +} + +// Create a new node for the attached controller +void WirelessGamingReceiver::InstantiateService(int index) +{ + connections[index].service = new WirelessDevice; + if (connections[index].service != NULL) + { + const OSString *keys[1] = { + OSString::withCString(kIOWirelessDeviceType), + }; + const OSObject *objects[1] = { + OSNumber::withNumber((unsigned long long)0, 32), + }; + OSDictionary *dictionary = OSDictionary::withObjects(objects, keys, 1, 0); + if (connections[index].service->init(dictionary)) + { + connections[index].service->attach(this); + connections[index].service->SetIndex(index); +// connections[index].service->registerService(); +// IOLog("process: Device attached\n"); + if (IsDataQueued(index)) + connections[index].service->NewData(); + connections[index].service->start(this); + } + else + { + connections[index].service->release(); + connections[index].service = NULL; +// IOLog("process: Device attach failure\n"); + } + } +} + +// Check a controller's queue +bool WirelessGamingReceiver::IsDataQueued(int index) +{ + return connections[index].inputArray->getCount() > 0; +} + +// Read a controller's queue +IOMemoryDescriptor* WirelessGamingReceiver::ReadBuffer(int index) +{ + IOMemoryDescriptor *data; + + data = OSDynamicCast(IOMemoryDescriptor, connections[index].inputArray->getObject(0)); + if (data != NULL) + data->retain(); + connections[index].inputArray->removeObject(0); + return data; +} + +// Get our location ID +OSNumber* WirelessGamingReceiver::newLocationIDNumber() const +{ + OSNumber *number; + UInt32 location = 0; + + if (device) + { + if ((number = OSDynamicCast(OSNumber, device->getProperty("locationID")))) + { + location = number->unsigned32BitValue(); + } + else + { + // Make up an address + if ((number = OSDynamicCast(OSNumber, device->getProperty("USB Address")))) + location |= number->unsigned8BitValue() << 24; + + if ((number = OSDynamicCast(OSNumber, device->getProperty("idProduct")))) + location |= number->unsigned8BitValue() << 16; + } + } + + return OSNumber::withNumber(location, 32); +} diff --git a/WirelessGamingReceiver/WirelessGamingReceiver.h b/WirelessGamingReceiver/WirelessGamingReceiver.h new file mode 100644 index 00000000..41c65d68 --- /dev/null +++ b/WirelessGamingReceiver/WirelessGamingReceiver.h @@ -0,0 +1,89 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + WirelessGamingReceiver.h - declaration of the wireless receiver driver + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef __WIRELESSGAMINGRECEIVER_H__ +#define __WIRELESSGAMINGRECEIVER_H__ + +#include +#include + +// This value is defined by the hardware and fixed +#define WIRELESS_CONNECTIONS 4 + +class WirelessDevice; + +typedef struct +{ + // Controller + IOUSBInterface *controller; + IOUSBPipe *controllerIn, *controllerOut; + + // Mystery + IOUSBInterface *other; + IOUSBPipe *otherIn, *otherOut; + + // Runtime data + OSArray *inputArray; + WirelessDevice *service; + bool controllerStarted; +} +WIRELESS_CONNECTION; + +class WirelessGamingReceiver : public IOService +{ + OSDeclareDefaultStructors(WirelessGamingReceiver); +public: + bool start(IOService *provider); + void stop(IOService *provider); + + IOReturn message(UInt32 type,IOService *provider,void *argument); + + // For WirelessDevice to use + OSNumber* newLocationIDNumber() const; + +private: + friend class WirelessDevice; + bool IsDataQueued(int index); + IOMemoryDescriptor* ReadBuffer(int index); + bool QueueWrite(int index, const void *bytes, UInt32 length); + +private: + IOUSBDevice *device; + WIRELESS_CONNECTION connections[WIRELESS_CONNECTIONS]; + int connectionCount; + + void InstantiateService(int index); + + void ProcessMessage(int index, const unsigned char *data, int length); + + bool QueueRead(int index); + void ReadComplete(void *parameter, IOReturn status, UInt32 bufferSizeRemaining); + + void WriteComplete(void *parameter, IOReturn status, UInt32 bufferSizeRemaining); + + void ReleaseAll(void); + + static void _ReadComplete(void *target, void *parameter, IOReturn status, UInt32 bufferSizeRemaining); + static void _WriteComplete(void *target, void *parameter, IOReturn status, UInt32 bufferSizeRemaining); +}; + +#endif // __WIRELESSGAMINGRECEIVER_H__ diff --git a/WirelessGamingReceiver/WirelessGamingReceiver.xcodeproj/colin.mode1 b/WirelessGamingReceiver/WirelessGamingReceiver.xcodeproj/colin.mode1 new file mode 100644 index 00000000..6405cf09 --- /dev/null +++ b/WirelessGamingReceiver/WirelessGamingReceiver.xcodeproj/colin.mode1 @@ -0,0 +1,1564 @@ + + + + + ActivePerspectiveName + Project + AllowedModules + + + BundleLoadPath + + MaxInstances + n + Module + PBXSmartGroupTreeModule + Name + Groups and Files Outline View + + + BundleLoadPath + + MaxInstances + n + Module + PBXNavigatorGroup + Name + Editor + + + BundleLoadPath + + MaxInstances + n + Module + XCTaskListModule + Name + Task List + + + BundleLoadPath + + MaxInstances + n + Module + XCDetailModule + Name + File and Smart Group Detail Viewer + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXBuildResultsModule + Name + Detailed Build Results Viewer + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXProjectFindModule + Name + Project Batch Find Tool + + + BundleLoadPath + + MaxInstances + n + Module + PBXRunSessionModule + Name + Run Log + + + BundleLoadPath + + MaxInstances + n + Module + PBXBookmarksModule + Name + Bookmarks Tool + + + BundleLoadPath + + MaxInstances + n + Module + PBXClassBrowserModule + Name + Class Browser + + + BundleLoadPath + + MaxInstances + n + Module + PBXCVSModule + Name + Source Code Control Tool + + + BundleLoadPath + + MaxInstances + n + Module + PBXDebugBreakpointsModule + Name + Debug Breakpoints Tool + + + BundleLoadPath + + MaxInstances + n + Module + XCDockableInspector + Name + Inspector + + + BundleLoadPath + + MaxInstances + n + Module + PBXOpenQuicklyModule + Name + Open Quickly Tool + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXDebugSessionModule + Name + Debugger + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXDebugCLIModule + Name + Debug Console + + + Description + DefaultDescriptionKey + DockingSystemVisible + + Extension + mode1 + FavBarConfig + + PBXProjectModuleGUID + 3B21EBD60B8CEAED00B5CACA + XCBarModuleItemNames + + XCBarModuleItems + + + FirstTimeWindowDisplayed + + Identifier + com.apple.perspectives.project.mode1 + MajorVersion + 31 + MinorVersion + 1 + Name + Default + Notifications + + OpenEditors + + + Content + + PBXProjectModuleGUID + 3BE527360BDC379700984E1F + PBXProjectModuleLabel + WirelessGamingReceiver.cpp + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 3BE527370BDC379700984E1F + PBXProjectModuleLabel + WirelessGamingReceiver.cpp + _historyCapacity + 0 + bookmark + 3BD5A2FD0C56D76C005B4E24 + history + + 3BD5A2FC0C56D76C005B4E24 + + + SplitCount + 1 + + StatusBarVisibility + + + Geometry + + Frame + {{0, 20}, {806, 677}} + PBXModuleWindowStatusBarHidden2 + + RubberWindowFrame + 38 258 806 718 0 0 1280 1002 + + + + Content + + PBXProjectModuleGUID + 3B54B4630BDA9ECF00329AC0 + PBXProjectModuleLabel + WirelessHIDDevice.cpp + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 3B54B4640BDA9ECF00329AC0 + PBXProjectModuleLabel + WirelessHIDDevice.cpp + _historyCapacity + 0 + bookmark + 3BD5A2FE0C56D76C005B4E24 + history + + 3B4FC9F60C49C3B3007CF491 + + + SplitCount + 1 + + StatusBarVisibility + + + Geometry + + Frame + {{0, 20}, {1059, 503}} + PBXModuleWindowStatusBarHidden2 + + RubberWindowFrame + 34 458 1059 544 0 0 1280 1002 + + + + Content + + PBXProjectModuleGUID + 3BD1A9390C49BC33006510F7 + PBXProjectModuleLabel + WirelessHIDDevice.h + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 3BD1A93A0C49BC33006510F7 + PBXProjectModuleLabel + WirelessHIDDevice.h + _historyCapacity + 0 + bookmark + 3BD5A2FF0C56D76C005B4E24 + history + + 3B4FC9F70C49C3B3007CF491 + + + SplitCount + 1 + + StatusBarVisibility + + + Geometry + + Frame + {{0, 20}, {1059, 503}} + PBXModuleWindowStatusBarHidden2 + + RubberWindowFrame + 155 150 1059 544 0 0 1280 1002 + + + + Content + + PBXProjectModuleGUID + 3B216B380C08E9A4000BE7F3 + PBXProjectModuleLabel + WirelessGamingReceiver.h + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 3B216B390C08E9A4000BE7F3 + PBXProjectModuleLabel + WirelessGamingReceiver.h + _historyCapacity + 0 + bookmark + 3BD5A3000C56D76C005B4E24 + history + + 3B4FC9F80C49C3B3007CF491 + + + SplitCount + 1 + + StatusBarVisibility + + + Geometry + + Frame + {{0, 20}, {688, 361}} + PBXModuleWindowStatusBarHidden2 + + RubberWindowFrame + 481 168 688 402 0 0 1280 1002 + + + + Content + + PBXProjectModuleGUID + 3B216B3B0C08E9A4000BE7F3 + PBXProjectModuleLabel + IOUSBDevice.cpp + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 3B216B3C0C08E9A4000BE7F3 + PBXProjectModuleLabel + IOUSBDevice.cpp + _historyCapacity + 0 + bookmark + 3BD5A3010C56D76C005B4E24 + history + + 3B4FC9F90C49C3B3007CF491 + + + SplitCount + 1 + + StatusBarVisibility + + + Geometry + + Frame + {{0, 20}, {806, 677}} + PBXModuleWindowStatusBarHidden2 + + RubberWindowFrame + 61 237 806 718 0 0 1280 1002 + + + + Content + + PBXProjectModuleGUID + 3B216B410C08E9A4000BE7F3 + PBXProjectModuleLabel + WirelessDevice.h + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 3B216B420C08E9A4000BE7F3 + PBXProjectModuleLabel + WirelessDevice.h + _historyCapacity + 0 + bookmark + 3BD5A3030C56D76C005B4E24 + history + + 3B4FC9FB0C49C3B3007CF491 + + + SplitCount + 1 + + StatusBarVisibility + + + Geometry + + Frame + {{0, 20}, {1059, 503}} + PBXModuleWindowStatusBarHidden2 + + RubberWindowFrame + 175 169 1059 544 0 0 1280 1002 + + + + PerspectiveWidths + + -1 + -1 + + Perspectives + + + ChosenToolbarItems + + active-target-popup + active-buildstyle-popup + action + NSToolbarFlexibleSpaceItem + buildOrClean + build-and-runOrDebug + com.apple.ide.PBXToolbarStopButton + get-info + toggle-editor + NSToolbarFlexibleSpaceItem + com.apple.pbx.toolbar.searchfield + + ControllerClassBaseName + + IconName + WindowOfProjectWithEditor + Identifier + perspective.project + IsVertical + + Layout + + + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C08E77C0454961000C914BD + 1C37FABC05509CD000000102 + 1C37FABC05539CD112110102 + E2644B35053B69B200211256 + 1C37FABC04509CD000100104 + 1CC0EA4004350EF90044410B + 1CC0EA4004350EF90041110B + + PBXProjectModuleGUID + 1CE0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + yes + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 186 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 089C166AFE841209C02AAC07 + 1C37FABC05509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {186, 338}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + + XCSharingToken + com.apple.Xcode.GFSharingToken + + GeometryConfiguration + + Frame + {{0, 0}, {203, 356}} + GroupTreeTableConfiguration + + MainColumn + 186 + + RubberWindowFrame + 7 576 690 397 0 0 1280 1002 + + Module + PBXSmartGroupTreeModule + Proportion + 203pt + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CE0B20306471E060097A5F4 + PBXProjectModuleLabel + MyNewFile14.java + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1CE0B20406471E060097A5F4 + PBXProjectModuleLabel + MyNewFile14.java + + SplitCount + 1 + + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {482, 0}} + RubberWindowFrame + 7 576 690 397 0 0 1280 1002 + + Module + PBXNavigatorGroup + Proportion + 0pt + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1CE0B20506471E060097A5F4 + PBXProjectModuleLabel + Detail + + GeometryConfiguration + + Frame + {{0, 5}, {482, 351}} + RubberWindowFrame + 7 576 690 397 0 0 1280 1002 + + Module + XCDetailModule + Proportion + 351pt + + + Proportion + 482pt + + + Name + Project + ServiceClasses + + XCModuleDock + PBXSmartGroupTreeModule + XCModuleDock + PBXNavigatorGroup + XCDetailModule + + TableOfContents + + 3BD5A2FA0C56D76C005B4E24 + 1CE0B1FE06471DED0097A5F4 + 3BD5A2FB0C56D76C005B4E24 + 1CE0B20306471E060097A5F4 + 1CE0B20506471E060097A5F4 + + ToolbarConfiguration + xcode.toolbar.config.default + + + ControllerClassBaseName + + IconName + WindowOfProject + Identifier + perspective.morph + IsVertical + 0 + Layout + + + BecomeActive + 1 + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C08E77C0454961000C914BD + 1C37FABC05509CD000000102 + 1C37FABC05539CD112110102 + E2644B35053B69B200211256 + 1C37FABC04509CD000100104 + 1CC0EA4004350EF90044410B + 1CC0EA4004350EF90041110B + + PBXProjectModuleGUID + 11E0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + yes + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 186 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 29B97314FDCFA39411CA2CEA + 1C37FABC05509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {186, 337}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + 1 + XCSharingToken + com.apple.Xcode.GFSharingToken + + GeometryConfiguration + + Frame + {{0, 0}, {203, 355}} + GroupTreeTableConfiguration + + MainColumn + 186 + + RubberWindowFrame + 373 269 690 397 0 0 1440 878 + + Module + PBXSmartGroupTreeModule + Proportion + 100% + + + Name + Morph + PreferredWidth + 300 + ServiceClasses + + XCModuleDock + PBXSmartGroupTreeModule + + TableOfContents + + 11E0B1FE06471DED0097A5F4 + + ToolbarConfiguration + xcode.toolbar.config.default.short + + + PerspectivesBarVisible + + ShelfIsVisible + + SourceDescription + file at '/System/Library/PrivateFrameworks/DevToolsInterface.framework/Versions/A/Resources/XCPerspectivesSpecificationMode1.xcperspec' + StatusbarIsVisible + + TimeStamp + 0.0 + ToolbarDisplayMode + 1 + ToolbarIsVisible + + ToolbarSizeMode + 1 + Type + Perspectives + UpdateMessage + The Default Workspace in this version of Xcode now includes support to hide and show the detail view (what has been referred to as the "Metro-Morph" feature). You must discard your current Default Workspace settings and update to the latest Default Workspace in order to gain this feature. Do you wish to update to the latest Workspace defaults for project '%@'? + WindowJustification + 5 + WindowOrderList + + 3B21ED2D0B8E33A000B5CACA + 3B216B410C08E9A4000BE7F3 + 3B216B3B0C08E9A4000BE7F3 + 3B216B380C08E9A4000BE7F3 + 3BD1A9390C49BC33006510F7 + 3B54B4630BDA9ECF00329AC0 + /Users/colin/Projects2/OSX/360 Controller/WirelessGamingReceiver/WirelessGamingReceiver.xcodeproj + 3BE527360BDC379700984E1F + + WindowString + 7 576 690 397 0 0 1280 1002 + WindowTools + + + FirstTimeWindowDisplayed + + Identifier + windowTool.build + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528F0623707200166675 + PBXProjectModuleLabel + + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {668, 312}} + RubberWindowFrame + 36 380 668 594 0 0 1280 1002 + + Module + PBXNavigatorGroup + Proportion + 312pt + + + ContentConfiguration + + PBXProjectModuleGUID + XCMainBuildResultsModuleGUID + PBXProjectModuleLabel + Build + XCBuildResultsTrigger_Collapse + 1021 + XCBuildResultsTrigger_Open + 1011 + + GeometryConfiguration + + Frame + {{0, 317}, {668, 236}} + RubberWindowFrame + 36 380 668 594 0 0 1280 1002 + + Module + PBXBuildResultsModule + Proportion + 236pt + + + Proportion + 553pt + + + Name + Build Results + ServiceClasses + + PBXBuildResultsModule + + StatusbarIsVisible + + TableOfContents + + 3B21ED2D0B8E33A000B5CACA + 3BD5A3040C56D76C005B4E24 + 1CD0528F0623707200166675 + XCMainBuildResultsModuleGUID + + ToolbarConfiguration + xcode.toolbar.config.build + WindowString + 36 380 668 594 0 0 1280 1002 + WindowToolGUID + 3B21ED2D0B8E33A000B5CACA + WindowToolIsVisible + + + + Identifier + windowTool.debugger + Layout + + + Dock + + + ContentConfiguration + + Debugger + + HorizontalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {317, 164}} + {{317, 0}, {377, 164}} + + + VerticalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {694, 164}} + {{0, 164}, {694, 216}} + + + + LauncherConfigVersion + 8 + PBXProjectModuleGUID + 1C162984064C10D400B95A72 + PBXProjectModuleLabel + Debug - GLUTExamples (Underwater) + + GeometryConfiguration + + DebugConsoleDrawerSize + {100, 120} + DebugConsoleVisible + None + DebugConsoleWindowFrame + {{200, 200}, {500, 300}} + DebugSTDIOWindowFrame + {{200, 200}, {500, 300}} + Frame + {{0, 0}, {694, 380}} + RubberWindowFrame + 321 238 694 422 0 0 1440 878 + + Module + PBXDebugSessionModule + Proportion + 100% + + + Proportion + 100% + + + Name + Debugger + ServiceClasses + + PBXDebugSessionModule + + StatusbarIsVisible + 1 + TableOfContents + + 1CD10A99069EF8BA00B06720 + 1C0AD2AB069F1E9B00FABCE6 + 1C162984064C10D400B95A72 + 1C0AD2AC069F1E9B00FABCE6 + + ToolbarConfiguration + xcode.toolbar.config.debug + WindowString + 321 238 694 422 0 0 1440 878 + WindowToolGUID + 1CD10A99069EF8BA00B06720 + WindowToolIsVisible + 0 + + + FirstTimeWindowDisplayed + + Identifier + windowTool.find + IsVertical + + Layout + + + Dock + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CDD528C0622207200134675 + PBXProjectModuleLabel + + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {781, 212}} + RubberWindowFrame + 53 509 781 470 0 0 1280 1002 + + Module + PBXNavigatorGroup + Proportion + 781pt + + + Proportion + 212pt + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528E0623707200166675 + PBXProjectModuleLabel + Project Find + + GeometryConfiguration + + Frame + {{0, 217}, {781, 212}} + RubberWindowFrame + 53 509 781 470 0 0 1280 1002 + + Module + PBXProjectFindModule + Proportion + 212pt + + + Proportion + 429pt + + + Name + Project Find + ServiceClasses + + PBXProjectFindModule + + StatusbarIsVisible + + TableOfContents + + 1C530D57069F1CE1000CFCEE + 3BCC40340BDA6D7200B1619B + 3BCC40350BDA6D7200B1619B + 1CDD528C0622207200134675 + 1CD0528E0623707200166675 + + WindowString + 53 509 781 470 0 0 1280 1002 + WindowToolGUID + 1C530D57069F1CE1000CFCEE + WindowToolIsVisible + + + + Identifier + MENUSEPARATOR + + + Identifier + windowTool.debuggerConsole + Layout + + + Dock + + + BecomeActive + 1 + ContentConfiguration + + PBXProjectModuleGUID + 1C78EAAC065D492600B07095 + PBXProjectModuleLabel + Debugger Console + + GeometryConfiguration + + Frame + {{0, 0}, {440, 358}} + RubberWindowFrame + 650 41 440 400 0 0 1280 1002 + + Module + PBXDebugCLIModule + Proportion + 358pt + + + Proportion + 358pt + + + Name + Debugger Console + ServiceClasses + + PBXDebugCLIModule + + StatusbarIsVisible + 1 + TableOfContents + + 1C78EAAD065D492600B07095 + 1C78EAAE065D492600B07095 + 1C78EAAC065D492600B07095 + + WindowString + 650 41 440 400 0 0 1280 1002 + + + Identifier + windowTool.run + Layout + + + Dock + + + ContentConfiguration + + LauncherConfigVersion + 3 + PBXProjectModuleGUID + 1CD0528B0623707200166675 + PBXProjectModuleLabel + Run + Runner + + HorizontalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {493, 167}} + {{0, 176}, {493, 267}} + + + VerticalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {405, 443}} + {{414, 0}, {514, 443}} + + + + + GeometryConfiguration + + Frame + {{0, 0}, {460, 159}} + RubberWindowFrame + 316 696 459 200 0 0 1280 1002 + + Module + PBXRunSessionModule + Proportion + 159pt + + + Proportion + 159pt + + + Name + Run Log + ServiceClasses + + PBXRunSessionModule + + StatusbarIsVisible + 1 + TableOfContents + + 1C0AD2B3069F1EA900FABCE6 + 1C0AD2B4069F1EA900FABCE6 + 1CD0528B0623707200166675 + 1C0AD2B5069F1EA900FABCE6 + + ToolbarConfiguration + xcode.toolbar.config.run + WindowString + 316 696 459 200 0 0 1280 1002 + WindowToolGUID + 1C0AD2B3069F1EA900FABCE6 + WindowToolIsVisible + 0 + + + Identifier + windowTool.scm + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1C78EAB2065D492600B07095 + PBXProjectModuleLabel + <No Editor> + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1C78EAB3065D492600B07095 + + SplitCount + 1 + + StatusBarVisibility + 1 + + GeometryConfiguration + + Frame + {{0, 0}, {452, 0}} + RubberWindowFrame + 743 379 452 308 0 0 1280 1002 + + Module + PBXNavigatorGroup + Proportion + 0pt + + + BecomeActive + 1 + ContentConfiguration + + PBXProjectModuleGUID + 1CD052920623707200166675 + PBXProjectModuleLabel + SCM + + GeometryConfiguration + + ConsoleFrame + {{0, 259}, {452, 0}} + Frame + {{0, 7}, {452, 259}} + RubberWindowFrame + 743 379 452 308 0 0 1280 1002 + TableConfiguration + + Status + 30 + FileName + 199 + Path + 197.09500122070312 + + TableFrame + {{0, 0}, {452, 250}} + + Module + PBXCVSModule + Proportion + 262pt + + + Proportion + 266pt + + + Name + SCM + ServiceClasses + + PBXCVSModule + + StatusbarIsVisible + 1 + TableOfContents + + 1C78EAB4065D492600B07095 + 1C78EAB5065D492600B07095 + 1C78EAB2065D492600B07095 + 1CD052920623707200166675 + + ToolbarConfiguration + xcode.toolbar.config.scm + WindowString + 743 379 452 308 0 0 1280 1002 + + + Identifier + windowTool.breakpoints + IsVertical + 0 + Layout + + + Dock + + + BecomeActive + 1 + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C77FABC04509CD000000102 + + PBXProjectModuleGUID + 1CE0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + no + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 168 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 1C77FABC04509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {168, 350}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + 0 + + GeometryConfiguration + + Frame + {{0, 0}, {185, 368}} + GroupTreeTableConfiguration + + MainColumn + 168 + + RubberWindowFrame + 315 424 744 409 0 0 1440 878 + + Module + PBXSmartGroupTreeModule + Proportion + 185pt + + + ContentConfiguration + + PBXProjectModuleGUID + 1CA1AED706398EBD00589147 + PBXProjectModuleLabel + Detail + + GeometryConfiguration + + Frame + {{190, 0}, {554, 368}} + RubberWindowFrame + 315 424 744 409 0 0 1440 878 + + Module + XCDetailModule + Proportion + 554pt + + + Proportion + 368pt + + + MajorVersion + 2 + MinorVersion + 0 + Name + Breakpoints + ServiceClasses + + PBXSmartGroupTreeModule + XCDetailModule + + StatusbarIsVisible + 1 + TableOfContents + + 1CDDB66807F98D9800BB5817 + 1CDDB66907F98D9800BB5817 + 1CE0B1FE06471DED0097A5F4 + 1CA1AED706398EBD00589147 + + ToolbarConfiguration + xcode.toolbar.config.breakpoints + WindowString + 315 424 744 409 0 0 1440 878 + WindowToolGUID + 1CDDB66807F98D9800BB5817 + WindowToolIsVisible + 1 + + + Identifier + windowTool.debugAnimator + Layout + + + Dock + + + Module + PBXNavigatorGroup + Proportion + 100% + + + Proportion + 100% + + + Name + Debug Visualizer + ServiceClasses + + PBXNavigatorGroup + + StatusbarIsVisible + 1 + ToolbarConfiguration + xcode.toolbar.config.debugAnimator + WindowString + 100 100 700 500 0 0 1280 1002 + + + Identifier + windowTool.bookmarks + Layout + + + Dock + + + Module + PBXBookmarksModule + Proportion + 100% + + + Proportion + 100% + + + Name + Bookmarks + ServiceClasses + + PBXBookmarksModule + + StatusbarIsVisible + 0 + WindowString + 538 42 401 187 0 0 1280 1002 + + + Identifier + windowTool.classBrowser + Layout + + + Dock + + + BecomeActive + 1 + ContentConfiguration + + OptionsSetName + Hierarchy, all classes + PBXProjectModuleGUID + 1CA6456E063B45B4001379D8 + PBXProjectModuleLabel + Class Browser - NSObject + + GeometryConfiguration + + ClassesFrame + {{0, 0}, {374, 96}} + ClassesTreeTableConfiguration + + PBXClassNameColumnIdentifier + 208 + PBXClassBookColumnIdentifier + 22 + + Frame + {{0, 0}, {630, 331}} + MembersFrame + {{0, 105}, {374, 395}} + MembersTreeTableConfiguration + + PBXMemberTypeIconColumnIdentifier + 22 + PBXMemberNameColumnIdentifier + 216 + PBXMemberTypeColumnIdentifier + 97 + PBXMemberBookColumnIdentifier + 22 + + PBXModuleWindowStatusBarHidden2 + 1 + RubberWindowFrame + 385 179 630 352 0 0 1440 878 + + Module + PBXClassBrowserModule + Proportion + 332pt + + + Proportion + 332pt + + + Name + Class Browser + ServiceClasses + + PBXClassBrowserModule + + StatusbarIsVisible + 0 + TableOfContents + + 1C0AD2AF069F1E9B00FABCE6 + 1C0AD2B0069F1E9B00FABCE6 + 1CA6456E063B45B4001379D8 + + ToolbarConfiguration + xcode.toolbar.config.classbrowser + WindowString + 385 179 630 352 0 0 1440 878 + WindowToolGUID + 1C0AD2AF069F1E9B00FABCE6 + WindowToolIsVisible + 0 + + + + diff --git a/WirelessGamingReceiver/WirelessGamingReceiver.xcodeproj/project.pbxproj b/WirelessGamingReceiver/WirelessGamingReceiver.xcodeproj/project.pbxproj new file mode 100644 index 00000000..cefc6790 --- /dev/null +++ b/WirelessGamingReceiver/WirelessGamingReceiver.xcodeproj/project.pbxproj @@ -0,0 +1,280 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 32D94FC60562CBF700B6AF17 /* WirelessGamingReceiver.h in Headers */ = {isa = PBXBuildFile; fileRef = 1A224C3EFF42367911CA2CB7 /* WirelessGamingReceiver.h */; }; + 32D94FC80562CBF700B6AF17 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C167DFE841241C02AAC07 /* InfoPlist.strings */; }; + 32D94FCA0562CBF700B6AF17 /* WirelessGamingReceiver.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A224C3FFF42367911CA2CB7 /* WirelessGamingReceiver.cpp */; settings = {ATTRIBUTES = (); }; }; + 3B21ED670B8E688A00B5CACA /* WirelessDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 3B21ED660B8E688A00B5CACA /* WirelessDevice.h */; }; + 3B21ED6C0B8E690F00B5CACA /* WirelessDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3B21ED6B0B8E690F00B5CACA /* WirelessDevice.cpp */; }; + 3BE667180B9109C5009679FC /* WirelessHIDDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BE667170B9109C5009679FC /* WirelessHIDDevice.h */; }; + 3BE6671C0B910A02009679FC /* WirelessHIDDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3BE6671B0B910A02009679FC /* WirelessHIDDevice.cpp */; }; + 3BE6677B0B91DC55009679FC /* devices.h in Headers */ = {isa = PBXBuildFile; fileRef = 3BE6677A0B91DC55009679FC /* devices.h */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 089C167EFE841241C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + 1A224C3EFF42367911CA2CB7 /* WirelessGamingReceiver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WirelessGamingReceiver.h; sourceTree = ""; }; + 1A224C3FFF42367911CA2CB7 /* WirelessGamingReceiver.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WirelessGamingReceiver.cpp; sourceTree = ""; }; + 32D94FCF0562CBF700B6AF17 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 32D94FD00562CBF700B6AF17 /* WirelessGamingReceiver.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WirelessGamingReceiver.kext; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B21ED660B8E688A00B5CACA /* WirelessDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WirelessDevice.h; sourceTree = ""; }; + 3B21ED6B0B8E690F00B5CACA /* WirelessDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WirelessDevice.cpp; sourceTree = ""; }; + 3BE667170B9109C5009679FC /* WirelessHIDDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WirelessHIDDevice.h; sourceTree = ""; }; + 3BE6671B0B910A02009679FC /* WirelessHIDDevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WirelessHIDDevice.cpp; sourceTree = ""; }; + 3BE6677A0B91DC55009679FC /* devices.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = devices.h; sourceTree = ""; }; + 8DA8362C06AD9B9200E5AC22 /* Kernel.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Kernel.framework; path = /System/Library/Frameworks/Kernel.framework; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 32D94FCB0562CBF700B6AF17 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 089C166AFE841209C02AAC07 /* WirelessGamingReceiver */ = { + isa = PBXGroup; + children = ( + 247142CAFF3F8F9811CA285C /* Source */, + 8DA8362C06AD9B9200E5AC22 /* Kernel.framework */, + 089C167CFE841241C02AAC07 /* Resources */, + 19C28FB6FE9D52B211CA2CBB /* Products */, + ); + name = WirelessGamingReceiver; + sourceTree = ""; + }; + 089C167CFE841241C02AAC07 /* Resources */ = { + isa = PBXGroup; + children = ( + 32D94FCF0562CBF700B6AF17 /* Info.plist */, + 089C167DFE841241C02AAC07 /* InfoPlist.strings */, + ); + name = Resources; + sourceTree = ""; + }; + 19C28FB6FE9D52B211CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 32D94FD00562CBF700B6AF17 /* WirelessGamingReceiver.kext */, + ); + name = Products; + sourceTree = ""; + }; + 247142CAFF3F8F9811CA285C /* Source */ = { + isa = PBXGroup; + children = ( + 3BE6677A0B91DC55009679FC /* devices.h */, + 3BE6671B0B910A02009679FC /* WirelessHIDDevice.cpp */, + 3BE667170B9109C5009679FC /* WirelessHIDDevice.h */, + 3B21ED6B0B8E690F00B5CACA /* WirelessDevice.cpp */, + 3B21ED660B8E688A00B5CACA /* WirelessDevice.h */, + 1A224C3FFF42367911CA2CB7 /* WirelessGamingReceiver.cpp */, + 1A224C3EFF42367911CA2CB7 /* WirelessGamingReceiver.h */, + ); + name = Source; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 32D94FC50562CBF700B6AF17 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 32D94FC60562CBF700B6AF17 /* WirelessGamingReceiver.h in Headers */, + 3B21ED670B8E688A00B5CACA /* WirelessDevice.h in Headers */, + 3BE667180B9109C5009679FC /* WirelessHIDDevice.h in Headers */, + 3BE6677B0B91DC55009679FC /* devices.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 32D94FC30562CBF700B6AF17 /* WirelessGamingReceiver */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB91D908733DB10010E9CD /* Build configuration list for PBXNativeTarget "WirelessGamingReceiver" */; + buildPhases = ( + 32D94FC50562CBF700B6AF17 /* Headers */, + 32D94FC70562CBF700B6AF17 /* Resources */, + 32D94FC90562CBF700B6AF17 /* Sources */, + 32D94FCB0562CBF700B6AF17 /* Frameworks */, + 32D94FCC0562CBF700B6AF17 /* Rez */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = WirelessGamingReceiver; + productInstallPath = "$(SYSTEM_LIBRARY_DIR)/Extensions"; + productName = WirelessGamingReceiver; + productReference = 32D94FD00562CBF700B6AF17 /* WirelessGamingReceiver.kext */; + productType = "com.apple.product-type.kernel-extension.iokit"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 089C1669FE841209C02AAC07 /* Project object */ = { + isa = PBXProject; + buildConfigurationList = 1DEB91DD08733DB10010E9CD /* Build configuration list for PBXProject "WirelessGamingReceiver" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 089C166AFE841209C02AAC07 /* WirelessGamingReceiver */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 32D94FC30562CBF700B6AF17 /* WirelessGamingReceiver */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 32D94FC70562CBF700B6AF17 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 32D94FC80562CBF700B6AF17 /* InfoPlist.strings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXRezBuildPhase section */ + 32D94FCC0562CBF700B6AF17 /* Rez */ = { + isa = PBXRezBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXRezBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 32D94FC90562CBF700B6AF17 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 32D94FCA0562CBF700B6AF17 /* WirelessGamingReceiver.cpp in Sources */, + 3B21ED6C0B8E690F00B5CACA /* WirelessDevice.cpp in Sources */, + 3BE6671C0B910A02009679FC /* WirelessHIDDevice.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 089C167DFE841241C02AAC07 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 089C167EFE841241C02AAC07 /* English */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 1DEB91DA08733DB10010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "Developer ID Application: Colin Munro"; + COPY_PHASE_STRIP = NO; + CURRENT_PROJECT_VERSION = 1.0.0d12; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Extensions"; + MODULE_NAME = com.mice.driver.WirelessGamingReceiver; + MODULE_VERSION = 1.0.0d11; + PRODUCT_NAME = WirelessGamingReceiver; + PROVISIONING_PROFILE = ""; + WRAPPER_EXTENSION = kext; + ZERO_LINK = YES; + }; + name = Debug; + }; + 1DEB91DB08733DB10010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "Developer ID Application: Colin Munro"; + CURRENT_PROJECT_VERSION = 1.0.0d12; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_MODEL_TUNING = G5; + INFOPLIST_FILE = Info.plist; + INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Extensions"; + MODULE_NAME = com.mice.driver.WirelessGamingReceiver; + MODULE_VERSION = 1.0.0d11; + PRODUCT_NAME = WirelessGamingReceiver; + PROVISIONING_PROFILE = ""; + WRAPPER_EXTENSION = kext; + }; + name = Release; + }; + 1DEB91DE08733DB10010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = ""; + PREBINDING = NO; + SDKROOT = ""; + }; + name = Debug; + }; + 1DEB91DF08733DB10010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.5; + PREBINDING = NO; + SDKROOT = ""; + SYMROOT = build; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB91D908733DB10010E9CD /* Build configuration list for PBXNativeTarget "WirelessGamingReceiver" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB91DA08733DB10010E9CD /* Debug */, + 1DEB91DB08733DB10010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB91DD08733DB10010E9CD /* Build configuration list for PBXProject "WirelessGamingReceiver" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB91DE08733DB10010E9CD /* Debug */, + 1DEB91DF08733DB10010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 089C1669FE841209C02AAC07 /* Project object */; +} diff --git a/WirelessGamingReceiver/WirelessHIDDevice.cpp b/WirelessGamingReceiver/WirelessHIDDevice.cpp new file mode 100644 index 00000000..db7a1d00 --- /dev/null +++ b/WirelessGamingReceiver/WirelessHIDDevice.cpp @@ -0,0 +1,282 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + WirelessHIDDevice.cpp - generic wireless 360 device driver with HID support + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#include +#include +#include "WirelessHIDDevice.h" +#include "WirelessDevice.h" +#include "devices.h" + +#define POWEROFF_TIMEOUT (2 * 60) + +OSDefineMetaClassAndAbstractStructors(WirelessHIDDevice, IOHIDDevice) +#define super IOHIDDevice + +// Some sort of message to send +const char weirdStart[] = {0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + +void WirelessHIDDevice::ChatPadTimerActionWrapper(OSObject *owner, IOTimerEventSource *sender) +{ + WirelessHIDDevice *device; + + device = OSDynamicCast(WirelessHIDDevice, owner); + // Automatic shutoff + device->serialTimerCount++; + if (device->serialTimerCount > POWEROFF_TIMEOUT) + device->PowerOff(); + // Reset + sender->setTimeoutMS(1000); +} + +// Sets the LED with the same format as the wired controller +void WirelessHIDDevice::SetLEDs(int mode) +{ + char buf[] = {0x00, 0x00, 0x08, 0x40 + (mode % 0x0e), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + WirelessDevice *device; + + device = OSDynamicCast(WirelessDevice, getProvider()); + if (device != NULL) + { + device->SendPacket(buf, sizeof(buf)); + device->SendPacket(weirdStart, sizeof(weirdStart)); + } +} + +// Returns the battery level +unsigned char WirelessHIDDevice::GetBatteryLevel(void) +{ + return battery; +} + +void WirelessHIDDevice::PowerOff(void) +{ + char buf[] = {0x00, 0x00, 0x08, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + WirelessDevice *device; + + device = OSDynamicCast(WirelessDevice, getProvider()); + if (device != NULL) + { + device->SendPacket(buf, sizeof(buf)); +// device->SendPacket(weirdStart, sizeof(weirdStart)); + } +} + +// Called from userspace to do something, like set the LEDs +IOReturn WirelessHIDDevice::setReport(IOMemoryDescriptor *report, IOHIDReportType reportType, IOOptionBits options) +{ + char data[2]; + + if (report->readBytes(0, data, 2) < 2) + return kIOReturnUnsupported; + + switch (data[0]) { + case 0x01: // LED + if ((data[1] != report->getLength()) || (data[1] != 0x03)) + return kIOReturnUnsupported; + report->readBytes(2, data, 1); + SetLEDs(data[0]); + return kIOReturnSuccess; + case 0x02: // Power + PowerOff(); + return kIOReturnSuccess; + default: + return super::setReport(report, reportType, options); + } +} + +// Start up the driver +bool WirelessHIDDevice::handleStart(IOService *provider) +{ + WirelessDevice *device; + IOWorkLoop *workloop; + + if (!super::handleStart(provider)) + goto fail; + + device = OSDynamicCast(WirelessDevice, provider); + if (device == NULL) + goto fail; + + serialTimerCount = 0; + + serialTimer = IOTimerEventSource::timerEventSource(this, ChatPadTimerActionWrapper); + if (serialTimer == NULL) + { + IOLog("start - failed to create timer for chatpad\n"); + goto fail; + } + workloop = getWorkLoop(); + if ((workloop == NULL) || (workloop->addEventSource(serialTimer) != kIOReturnSuccess)) + { + IOLog("start - failed to connect timer for chatpad\n"); + goto fail; + } + + device->RegisterWatcher(this, _receivedData, NULL); + + device->SendPacket(weirdStart, sizeof(weirdStart)); + + serialTimer->setTimeoutMS(1000); + + return true; + +fail: + return false; +} + +// Shut down the driver +void WirelessHIDDevice::handleStop(IOService *provider) +{ + WirelessDevice *device; + + device = OSDynamicCast(WirelessDevice, provider); + if (device != NULL) + device->RegisterWatcher(NULL, NULL, NULL); + + if (serialTimer != NULL) { + serialTimer->cancelTimeout(); + IOWorkLoop *workloop = getWorkLoop(); + if (workloop != NULL) + workloop->removeEventSource(serialTimer); + serialTimer->release(); + serialTimer = NULL; + } + + super::handleStop(provider); +} + +// Handle new data from the device +void WirelessHIDDevice::receivedData(void) +{ + IOMemoryDescriptor *data; + WirelessDevice *device = OSDynamicCast(WirelessDevice, getProvider()); + if (device == NULL) + return; + + while ((data = device->NextPacket()) != NULL) + { + receivedMessage(data); + data->release(); + } +} + +const char *HexData = "0123456789ABCDEF"; + +// Process new data +void WirelessHIDDevice::receivedMessage(IOMemoryDescriptor *data) +{ + unsigned char buf[29]; + + if (data->getLength() != 29) + return; + + data->readBytes(0, buf, 29); + + switch (buf[1]) + { + case 0x0f: // Initial info + if (buf[16] == 0x13) + receivedUpdate(0x13, buf + 17); + serialString[0] = HexData[(buf[0x0A] & 0xF0) >> 4]; + serialString[1] = HexData[buf[0x0A] & 0x0F]; + serialString[2] = HexData[(buf[0x0B] & 0xF0) >> 4]; + serialString[3] = HexData[buf[0x0B] & 0x0F]; + serialString[4] = HexData[(buf[0x0C] & 0xF0) >> 4]; + serialString[5] = HexData[buf[0x0C] & 0x0F]; + serialString[6] = HexData[(buf[0x0D] & 0xF0) >> 4]; + serialString[7] = HexData[buf[0x0D] & 0x0F]; + serialString[8] = '\0'; + IOLog("Got serial number: %s", serialString); + break; + + case 0x01: // HID info update + if (buf[3] == 0xf0) + receivedHIDupdate(buf + 4, buf[5]); + break; + + case 0x00: // Info update + receivedUpdate(buf[3], buf + 4); + break; + + default: + break; + } +} + +// Received an update of a specific value +void WirelessHIDDevice::receivedUpdate(unsigned char type, unsigned char *data) +{ + switch (type) + { + case 0x13: // Battery level + battery = data[0]; + { + OSObject *prop = OSNumber::withNumber(battery, 8); + if (prop != NULL) + { + setProperty(kIOWirelessBatteryLevel, prop); + prop->release(); + } + } + break; + + default: + break; + } +} + +// Received a normal HID update from the device +void WirelessHIDDevice::receivedHIDupdate(unsigned char *data, int length) +{ + IOReturn err; + IOMemoryDescriptor *report; + + serialTimerCount = 0; + report = IOMemoryDescriptor::withAddress(data, length, kIODirectionNone); + err = handleReport(report, kIOHIDReportTypeInput); + report->release(); + if (err != kIOReturnSuccess) + IOLog("handleReport return: 0x%.8x\n", err); +} + +// Wrapper for notification of receiving data +void WirelessHIDDevice::_receivedData(void *target, WirelessDevice *sender, void *parameter) +{ + ((WirelessHIDDevice*)target)->receivedData(); +} + +// Get a location ID for this device, as some games require it +OSNumber* WirelessHIDDevice::newLocationIDNumber() const +{ + WirelessDevice *device; + + device = OSDynamicCast(WirelessDevice, getProvider()); + if (device == NULL) + return NULL; + return device->newLocationIDNumber(); +} + +// Get the serial number of the device +OSString* WirelessHIDDevice::newSerialNumberString() const +{ + return OSString::withCString(serialString); +} diff --git a/WirelessGamingReceiver/WirelessHIDDevice.h b/WirelessGamingReceiver/WirelessHIDDevice.h new file mode 100644 index 00000000..b2f3521f --- /dev/null +++ b/WirelessGamingReceiver/WirelessHIDDevice.h @@ -0,0 +1,60 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + WirelessHIDDevice.h - declaration of generic wireless HID device + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef __WIRELESSHIDDEVICE_H__ +#define __WIRELESSHIDDEVICE_H__ + +#include + +class WirelessDevice; + +class WirelessHIDDevice : public IOHIDDevice +{ + OSDeclareDefaultStructors(WirelessHIDDevice); +public: + void SetLEDs(int mode); + void PowerOff(void); + unsigned char GetBatteryLevel(void); + + IOReturn setReport(IOMemoryDescriptor *report, IOHIDReportType reportType, IOOptionBits options); + + OSNumber* newLocationIDNumber() const; + OSString* newSerialNumberString() const; +protected: + bool handleStart(IOService *provider); + void handleStop(IOService *provider); + virtual void receivedData(void); + virtual void receivedMessage(IOMemoryDescriptor *data); + virtual void receivedUpdate(unsigned char type, unsigned char *data); + virtual void receivedHIDupdate(unsigned char *data, int length); +private: + static void _receivedData(void *target, WirelessDevice *sender, void *parameter); + static void ChatPadTimerActionWrapper(OSObject *owner, IOTimerEventSource *sender); + + IOTimerEventSource *serialTimer; + int serialTimerCount; + + unsigned char battery; + char serialString[10]; +}; + +#endif // __WIRELESSHIDDEVICE_H__ diff --git a/WirelessGamingReceiver/devices.h b/WirelessGamingReceiver/devices.h new file mode 100644 index 00000000..81045194 --- /dev/null +++ b/WirelessGamingReceiver/devices.h @@ -0,0 +1,30 @@ +/* + MICE Xbox 360 Controller driver for Mac OS X + Copyright (C) 2006-2013 Colin Munro + + devics.h - contains constants for the wireless driver + + This file is part of Xbox360Controller. + + Xbox360Controller is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Xbox360Controller is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Foobar; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ +#ifndef __DEVICES_H__ +#define __DEVICES_H__ + +#define kIOWirelessDeviceType "Wireless360Device" + +#define kIOWirelessBatteryLevel "BatteryLevel" + +#endif // __DEVICES_H__ diff --git a/WirelessGamingReceiver/version.plist b/WirelessGamingReceiver/version.plist new file mode 100644 index 00000000..53bf3a3f --- /dev/null +++ b/WirelessGamingReceiver/version.plist @@ -0,0 +1,16 @@ + + + + + BuildVersion + 12 + CFBundleVersion + 1.0 + ProductBuildVersion + 7K571 + ProjectName + DevToolsWizardTemplates + SourceVersion + 3870000 + + diff --git a/build b/build new file mode 100755 index 00000000..65324c51 --- /dev/null +++ b/build @@ -0,0 +1,75 @@ +#!/bin/bash +zip -r ../360ControllerSource.zip * +cd Feedback360 +xcodebuild -configuration Deployment +if [ $? -ne 0 ] + then + echo "******** BUILD FAILED ********" + exit 1 +fi +cd ../DriverTool +xcodebuild -configuration Release +if [ $? -ne 0 ] + then + echo "******** BUILD FAILED ********" + exit 1 +fi +cd ../360Controller +xcodebuild -configuration Deployment +if [ $? -ne 0 ] + then + echo "******** BUILD FAILED ********" + exit 1 +fi +cd ../360Daemon +xcodebuild -configuration Release +if [ $? -ne 0 ] + then + echo "******** BUILD FAILED ********" + exit 1 +fi +cd ../WirelessGamingReceiver +xcodebuild -configuration Release +if [ $? -ne 0 ] + then + echo "******** BUILD FAILED ********" + exit 1 +fi +cd ../Wireless360Controller +xcodebuild -configuration Release +if [ $? -ne 0 ] + then + echo "******** BUILD FAILED ********" + exit 1 +fi +cd ../Pref360Control +xcodebuild -configuration Deployment +if [ $? -ne 0 ] + then + echo "******** BUILD FAILED ********" + exit 1 +fi +cd ../Install360Controller +packagesbuild -v Install360Controller.pkgproj +mv build 360ControllerInstall +hdiutil create -srcfolder 360ControllerInstall -format UDZO ../../360ControllerInstall.dmg +mv 360ControllerInstall build +cd .. +echo "** File contents **" +lipo -info 360Controller/build/Deployment/360Controller.kext/Contents/MacOS/360Controller +lipo -info 360Controller/build/Deployment/360Controller.kext/Contents/PlugIns/Feedback360.plugin/Contents/MacOS/Feedback360 +lipo -info 360Daemon/build/Release/360Daemon +lipo -info Pref360Control/build/Deployment/Pref360Control.prefPane/Contents/MacOS/Pref360Control +lipo -info Pref360Control/build/Deployment/Pref360Control.prefPane/Contents/Resources/DriverTool +lipo -info WirelessGamingReceiver/build/Release/WirelessGamingReceiver.kext/Contents/MacOS/WirelessGamingReceiver +lipo -info Wireless360Controller/build/Release/Wireless360Controller.kext/Contents/MacOS/Wireless360Controller +echo "** File signatures **" +sudo spctl -a -v 360Controller/build/Deployment/360Controller.kext +sudo spctl -a -v 360Controller/build/Deployment/360Controller.kext/Contents/PlugIns/Feedback360.plugin +sudo spctl -a -v 360Daemon/build/Release/360Daemon +sudo spctl -a -v Pref360Control/build/Deployment/Pref360Control.prefPane +sudo spctl -a -v Pref360Control/build/Deployment/Pref360Control.prefPane/Contents/Resources/DriverTool +sudo spctl -a -v WirelessGamingReceiver/build/Release/WirelessGamingReceiver.kext +sudo spctl -a -v Wireless360Controller/build/Release/Wireless360Controller.kext +sudo spctl -a -v --type install Install360Controller/build/Install360Controller.pkg +echo "*** DONE ***"